#!/usr/bin/perl

use Gtk2 '-init';
use Gtk2::Helper;
use IO::Socket::INET;
use IO::Select;
use IO::Socket;
use Config::Trivial;
use strict;
use Glib qw/TRUE FALSE/;
use Env qw(HOME);
use Astro::Time;

my $progname = "cDisko";
my $progvers = "4.0c";

# hashes to store our GUI and the data from the server
my %gui_elements;
my %gui_connections;
my %gui_markup;
my %settings;
my %status;

# read configuration file
my $config = Config::Trivial->new(config_file => "$HOME/.disko_config");
my $localsettings = $config->read;
&configfile_read_remote_hosts($localsettings);

# make some configuration checks
if (!defined $localsettings->{'antenna'}){
    die "No antenna location set: please set it in ~/.disko_config\n";
}
if (!defined $localsettings->{'server'}){
    die "No server specified: please set it in ~/.disko_config\n";
}
if (!defined $localsettings->{'listenport'}){
    $settings{'listenport'}=50081;
} else {
    $settings{'listenport'}=$localsettings->{'listenport'};
}
%{$settings{'antenna_names'}} = ( DSS43 => '43',
				  DSS45 => '45',
				  Hobart => 'Ho',
				  Ceduna => 'Cd',
				  Mopra => 'Mp',
				  ATCA => 'At',
				  Parkes => 'Pa',
				  Test => 'Tt' );

# set some colours
my %colours;
$colours{'red'}=Gtk2::Gdk::Color->parse('#ee4000');
$colours{'green'}=Gtk2::Gdk::Color->parse('#bcee68');
$colours{'yellow'}=Gtk2::Gdk::Color->parse('#ffff00');
$colours{'bone'}=Gtk2::Gdk::Color->parse('#ffffcc');
$colours{'white'}=Gtk2::Gdk::Color->parse('#fffaf0');

# set the available compression modes
&assign_compression_modes();

# start GUI creation
&make_gui();

&print2messageBuffer($progname." ".$progvers." starts");
#&print2messageBuffer("testing the print facility\neven with line breaks");

# make the socket listener for server messages
&make_listener();
# register with the recorder server
&register_listener();

# call the server query routine every few seconds
$settings{'queryInterval'}=10; # in seconds
# and the select poller every second
#$settings{'pollInterval'}=0.1; # in seconds
# the number of times to try connecting to the server before giving up
$settings{'n_retries'}=5;
# call the poller now
#&check_selector;
# call the query server routine now
&query_server;

# enter GUI main loop
Gtk2->main;

sub make_gui {

    # make our windows
    $gui_elements{'cdiskoMainWindow'}=Gtk2::Window->new;
    $gui_elements{'cdiskoMainWindow'}->signal_connect( destroy => sub {Gtk2->main_quit} );
    $gui_elements{'cdiskoMainWindow'}->set_title( $progname." ".$progvers );
    # we need a container that can contain more than one child, so we add a vbox
    $gui_elements{'cMW_mainContainer'}=Gtk2::VBox->new ( FALSE, 5 );
    $gui_elements{'cdiskoMainWindow'}->add($gui_elements{'cMW_mainContainer'});
    
    # our main window layout
    # the single line bar at the top of the main window indicating the server
    # we are connected to
    $gui_elements{'cMW_topBar'}=Gtk2::HBox->new ( FALSE, 5 );
    # the name of the antenna
    my $label1=Gtk2::Label->new();
    $label1->set_markup('<b>Station:</b>');
    $gui_elements{'cMW_topBar'}->pack_start($label1,FALSE,FALSE,4);
    my $antennalabel=Gtk2::Label->new($localsettings->{'antenna'});
    $gui_elements{'cMW_topBar'}->pack_start($antennalabel,FALSE,FALSE,4);
    # the connected server
    my $label2=Gtk2::Label->new();
    $label2->set_markup('<b>Server:</b>');
    $gui_elements{'cMW_topBar'}->pack_start($label2,FALSE,FALSE,4);
    my $serverlabel=Gtk2::Label->new($localsettings->{'server'});
    $gui_elements{'cMW_topBar'}->pack_start($serverlabel,FALSE,FALSE,4);
    # the server's uptime
    my $label3=Gtk2::Label->new();
    $label3->set_markup('<b>Uptime:</b>');
    $gui_elements{'cMW_topBar'}->pack_start($label3,FALSE,FALSE,4);
    $gui_elements{'cMW_tB_uptimeLabel'}=Gtk2::Label->new('Not connected');
    $gui_elements{'cMW_topBar'}->pack_start($gui_elements{'cMW_tB_uptimeLabel'},FALSE,FALSE,4);
    $gui_connections{'cMW_tB_uptimeLabel'}={element => \$gui_elements{'cMW_tB_uptimeLabel'},
					    data => 'status.server.time.uptime'};
    # the server's time
    my $label4=Gtk2::Label->new();
    $label4->set_markup('<b>Server Time:</b>');
    $gui_elements{'cMW_topBar'}->pack_start($label4,FALSE,FALSE,4);
    $gui_elements{'cMW_tB_serverTimeLabel'}=Gtk2::Label->new('Unknown');
    $gui_elements{'cMW_topBar'}->pack_start($gui_elements{'cMW_tB_serverTimeLabel'},FALSE,FALSE,4);
    $gui_connections{'cMW_tB_serverTimeLabel'}={element => \$gui_elements{'cMW_tB_serverTimeLabel'},
						data => 'status.server.time.serverTime'};
    # add the server line
    $gui_elements{'cMW_mainContainer'}->add($gui_elements{'cMW_topBar'});

    # the next line will show a summary of what the server is doing
    $gui_elements{'cMW_summaryBar'}=Gtk2::HBox->new ( FALSE, 5 );
    # the current recording state
    $gui_elements{'cMW_sB_recordingSummaryLabel'}=Gtk2::Button->new('Not recording');
    &button_background_colour(\$gui_elements{'cMW_sB_recordingSummaryLabel'},'bone');
    $gui_elements{'cMW_summaryBar'}->pack_start($gui_elements{'cMW_sB_recordingSummaryLabel'},FALSE,FALSE,4);
    $gui_connections{'cMW_sB_recordingSummaryLabel'}={element => \$gui_elements{'cMW_sB_recordingSummaryLabel'},
						      data => 'status.server.recordingState',
						      type => 'button' };
#    $gui_elements{'cMW_sB_currentExperimentLabel'}=Gtk2::Label->new('current experiment goes here');
    $gui_elements{'cMW_sB_currentExperimentLabel'}=Gtk2::Button->new('current experiment goes here');
    &button_background_colour(\$gui_elements{'cMW_sB_currentExperimentLabel'},'white');
    $gui_elements{'cMW_summaryBar'}->pack_start($gui_elements{'cMW_sB_currentExperimentLabel'},FALSE,FALSE,4);
    $gui_connections{'cMW_sB_currentExperimentLabel'}={element => \$gui_elements{'cMW_sB_currentExperimentLabel'},
						       data => 'status.server.currentExperiment',
						       type => 'button' };
    $gui_elements{'cMW_sB_endTimeLabel'}=Gtk2::Label->new('end time goes here');
    $gui_elements{'cMW_summaryBar'}->pack_start($gui_elements{'cMW_sB_endTimeLabel'},FALSE,FALSE,4);
    $gui_connections{'cMW_sB_endTimeLabel'}={element => \$gui_elements{'cMW_sB_endTimeLabel'},
					     data => 'status.server.endTime'};
    $gui_elements{'cMW_sB_recorderControlButton'}=Gtk2::Button->new('Recorder Control');
    $gui_connections{'cMW_sB_recorderControlButton'}={
	element => \$gui_elements{'cMW_sB_recorderControlButton'},
	data => 'settings.recorderControl',
	type => 'button' };
    $gui_elements{'cMW_summaryBar'}->pack_start($gui_elements{'cMW_sB_recorderControlButton'},TRUE,TRUE,4);
    # add the summary line
    $gui_elements{'cMW_mainContainer'}->add($gui_elements{'cMW_summaryBar'});

    # make a frame to show the connected and available disks
    $gui_elements{'cMW_disksFrame'}=Gtk2::Frame->new();
    $gui_elements{'cMW_disksFrame'}->set_border_width(10);
    $gui_elements{'cMW_disksFrame'}->set_shadow_type('out');
    $gui_elements{'cMW_disksFrame'}->set_label('Available Disks');
    $gui_elements{'cMW_dF_tableBox'}=Gtk2::VBox->new ( FALSE, 5 );
    $gui_elements{'cMW_dF_tB_diskTable'}=Gtk2::Table->new(1,7,FALSE);
    my @diskTableHeadings=("Recorder","Disk Name","Label","Size","Remaining","% left","Time Left (h:m:s)");
    for (my $i=0;$i<=$#diskTableHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$diskTableHeadings[$i].'</b>');
	$gui_elements{'cMW_dF_tB_diskTable'}->attach_defaults($tablelabel,$i,$i+1,0,1);
    }
    $gui_elements{'cMW_dF_tB_remoteHostButton'}=Gtk2::Button->new('Remote Host Configuration');

    # add the frame
    $gui_elements{'cMW_dF_tableBox'}->pack_start($gui_elements{'cMW_dF_tB_diskTable'},TRUE,TRUE,4);
    $gui_elements{'cMW_dF_tableBox'}->pack_start($gui_elements{'cMW_dF_tB_remoteHostButton'},TRUE,TRUE,1);
    $gui_elements{'cMW_disksFrame'}->add($gui_elements{'cMW_dF_tableBox'});
    $gui_elements{'cMW_mainContainer'}->add($gui_elements{'cMW_disksFrame'});
    # make the recording button do something
    $gui_elements{'cMW_sB_recorderControlButton'}->signal_connect('clicked',\&recorder_action);

    # make a frame to show the settings manipulation buttons
    $gui_elements{'cMW_settingsFrame'}=Gtk2::Frame->new();
    $gui_elements{'cMW_settingsFrame'}->set_border_width(10);
    $gui_elements{'cMW_settingsFrame'}->set_shadow_type('out');
    $gui_elements{'cMW_settingsFrame'}->set_label('Available Settings');
    $gui_elements{'cMW_sF_settingsButtonsTableBox'}=Gtk2::VBox->new ( FALSE, 5 );
    $settings{'n_profile_columns'}=4;
    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}=Gtk2::Table->new(3,$settings{'n_profile_columns'},TRUE);
    $status{'number_settings_buttons'}=0;
    
    # add the frame
    $gui_elements{'cMW_sF_settingsButtonsTableBox'}->pack_start($gui_elements{'cMW_sF_sBTB_settingsButtonsTable'},
								TRUE,TRUE,4);
    $gui_elements{'cMW_settingsFrame'}->add($gui_elements{'cMW_sF_settingsButtonsTableBox'});
    $gui_elements{'cMW_mainContainer'}->add($gui_elements{'cMW_settingsFrame'});

    # add the new profile stuff
    my $newprofilelabel=Gtk2::Label->new();
    $newprofilelabel->set_markup('<b>New Profile Name</b>');
    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}->
	attach_defaults($newprofilelabel,$settings{'n_profile_columns'}-1,$settings{'n_profile_columns'},0,1);
    $gui_elements{'cMW_sF_sBTB_sBT_userInput_newProfileNameInput'}=Gtk2::Entry->new();
    $gui_connections{'cMW_sF_sBTB_sBT_userInput_newProfileNameInput'}={
	element => \$gui_elements{'cMW_sF_sBTB_sBT_userInput_newProfileNameInput'},
	data => 'status.client.newProfileName',
	type => 'text' };
    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}->
	attach_defaults($gui_elements{'cMW_sF_sBTB_sBT_userInput_newProfileNameInput'},
			$settings{'n_profile_columns'}-1,$settings{'n_profile_columns'},1,2);
    # add the buttons
    $gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'}=Gtk2::Button->new('Default');
    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}->attach_defaults($gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'},
								       0,$settings{'n_profile_columns'}-1,0,1);
    $gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'}->show;
    $gui_elements{'cMW_sF_sBTB_sBT_addSettingsButton'}=Gtk2::Button->new('Add');
    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}->attach_defaults($gui_elements{'cMW_sF_sBTB_sBT_addSettingsButton'},
								       $settings{'n_profile_columns'}-1,
								       $settings{'n_profile_columns'},2,3);
    $gui_elements{'cMW_sF_sBTB_sBT_addSettingsButton'}->show;

    # make a frame to show the server messages
    $gui_elements{'cMW_messagesFrame'}=Gtk2::Frame->new();
    $gui_elements{'cMW_messagesFrame'}->set_border_width(10);
    $gui_elements{'cMW_messagesFrame'}->set_shadow_type('out');
    $gui_elements{'cMW_messagesFrame'}->set_label('Server Messages');
    $gui_elements{'cMW_mF_scrolledWindow'}=Gtk2::ScrolledWindow->new(undef, undef);
    $gui_elements{'cMW_mF_scrolledWindow'}->set_shadow_type('etched-out');
    $gui_elements{'cMW_mF_scrolledWindow'}->set_policy('automatic','automatic');
    $gui_elements{'cMW_mF_scrolledWindow'}->set_size_request(500,100);
    $gui_elements{'cMW_mF_scrolledWindow'}->set_border_width(5);
    $gui_elements{'cMW_mF_messagesBuffer'}=Gtk2::TextBuffer->new(undef);
    $gui_elements{'cMW_mF_messagesContainer'}=Gtk2::TextView->new_with_buffer($gui_elements{'cMW_mF_messagesBuffer'});
    $gui_elements{'cMW_mF_messagesContainer'}->set_editable(FALSE);
    $gui_elements{'cMW_mF_messagesContainer'}->set_cursor_visible(FALSE);
    # make some text tags for different types of message
    $gui_elements{'cMW_mF_mB_normalTag'}=Gtk2::TextTag->new('normal');
    $gui_elements{'cMW_mF_mB_normalTag'}->set_property( foreground => 'black' );
    $gui_elements{'cMW_mF_mB_normalTag'}->set_property( family => 'monospace' );
    $gui_elements{'cMW_mF_messagesBuffer'}->get_tag_table->add($gui_elements{'cMW_mF_mB_normalTag'});
    $gui_elements{'cMW_mF_mB_errorTag'}=Gtk2::TextTag->new('error');
    $gui_elements{'cMW_mF_mB_errorTag'}->set_property( foreground => 'red' );
    $gui_elements{'cMW_mF_mB_errorTag'}->set_property( family => 'monospace' );
    $gui_elements{'cMW_mF_messagesBuffer'}->get_tag_table->add($gui_elements{'cMW_mF_mB_errorTag'});
    $gui_elements{'cMW_mF_mB_successTag'}=Gtk2::TextTag->new('success');
    $gui_elements{'cMW_mF_mB_successTag'}->set_property( foreground => 'blue' );
    $gui_elements{'cMW_mF_mB_successTag'}->set_property( family => 'monospace' );
    $gui_elements{'cMW_mF_messagesBuffer'}->get_tag_table->add($gui_elements{'cMW_mF_mB_successTag'});
    $gui_elements{'cMW_mF_mB_serverMessageTag'}=Gtk2::TextTag->new('serverMessage');
    $gui_elements{'cMW_mF_mB_serverMessageTag'}->set_property( foreground => 'purple' );
    $gui_elements{'cMW_mF_mB_serverMessageTag'}->set_property( family => 'monospace' );
    $gui_elements{'cMW_mF_messagesBuffer'}->get_tag_table->add($gui_elements{'cMW_mF_mB_serverMessageTag'});
    
    
    # add the frame
    $gui_elements{'cMW_mF_scrolledWindow'}->add($gui_elements{'cMW_mF_messagesContainer'});
    $gui_elements{'cMW_messagesFrame'}->add($gui_elements{'cMW_mF_scrolledWindow'});
    $gui_elements{'cMW_mainContainer'}->add($gui_elements{'cMW_messagesFrame'});

    # display the GUI
    $gui_elements{'cdiskoMainWindow'}->show_all;

    # make the default settings window
    $status{'number_settings_windows'}=0;
    &new_settings_window('Default');
    # connect the main window button to make this window appear
    $gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'}->signal_connect('clicked', sub {
	${$gui_elements{'cdiskoSettingsWindow'}}[0]->show_all;
    });
    # connect the add button to create a new profile
    $gui_elements{'cMW_sF_sBTB_sBT_addSettingsButton'}->signal_connect('clicked',\&add_profile);
    
    ${$gui_elements{'cdiskoSettingsWindow'}}[0]->show_all;

    # make the remote host window
    $gui_elements{'cdiskoRemoteHostWindow'}=Gtk2::Window->new;
    $gui_elements{'cdiskoRemoteHostWindow'}->signal_connect( delete_event => sub {
	$gui_elements{'cdiskoRemoteHostWindow'}->hide;
	return TRUE;
    });
    $gui_elements{'cdiskoRemoteHostWindow'}->set_title('Remote Hosts');
    $gui_elements{'cRHW_mainContainer'}=Gtk2::VBox->new ( FALSE, 5 );
    $gui_elements{'cdiskoRemoteHostWindow'}->add($gui_elements{'cRHW_mainContainer'});

    # a table with the enabled remote host configurations
    $gui_elements{'cRHW_enabledFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRHW_enabledFrame'}->set_border_width(10);
    $gui_elements{'cRHW_enabledFrame'}->set_shadow_type('out');
    $gui_elements{'cRHW_enabledFrame'}->set_label('Enabled Hosts');
    $gui_elements{'cRHW_eF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRHW_eF_tB_enabledTable'}=Gtk2::Table->new(1,7,FALSE);
    # a table with the available remote host configurations
    $gui_elements{'cRHW_availableFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRHW_availableFrame'}->set_border_width(10);
    $gui_elements{'cRHW_availableFrame'}->set_shadow_type('out');
    $gui_elements{'cRHW_availableFrame'}->set_label('Available Hosts');
    $gui_elements{'cRHW_aF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRHW_aF_tB_availableTable'}=Gtk2::Table->new(1,7,FALSE);
    # give the columns some labels, the same in each table
    my @hostTableHeadings=("Recorder","Hostname","Port","TCP Window Size","eVLBI","UDP");
    for (my $i=0;$i<=$#hostTableHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$hostTableHeadings[$i].'</b>');
	my $tablelabel2=Gtk2::Label->new();
	$tablelabel2->set_markup('<b>'.$hostTableHeadings[$i].'</b>');
	$gui_elements{'cRHW_eF_tB_enabledTable'}->attach_defaults($tablelabel,$i,$i+1,0,1);
	$gui_elements{'cRHW_aF_tB_availableTable'}->attach_defaults($tablelabel2,$i,$i+1,0,1);
	$gui_elements{'cRHW_eF_tB_enabledTable'}->set_col_spacing($i,10);
	$gui_elements{'cRHW_aF_tB_availableTable'}->set_col_spacing($i,10);
    }
    # a frame for specifying a new host
    $gui_elements{'cRHW_newHostFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRHW_newHostFrame'}->set_border_width(10);
    $gui_elements{'cRHW_newHostFrame'}->set_shadow_type('out');
    $gui_elements{'cRHW_newHostFrame'}->set_label('Specify New Host');
    $gui_elements{'cRHW_nHF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRHW_nHF_tB_newTable'}=Gtk2::Table->new(7,2,FALSE);
    my @newTableHeadings=("Nickname","Hostname","TCP Port #","TCP Window Size (kB)","UDP Datagram Size (kB)",
			  "eVLBI target?");
    my @newTableDatanames=('nickname','hostname','tcpport','tcpwindowsize','udpsize','evlbienabled');
    for (my $i=0;$i<=$#newTableHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$newTableHeadings[$i].':</b>');
	$tablelabel->set_alignment(1.0,0.5);
	$gui_elements{'cRHW_nHF_tB_newTable'}->attach($tablelabel,0,1,$i,$i+1,'fill','shrink',0,0);
	if ($newTableDatanames[$i] ne 'evlbienabled'){
	    $gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}=
		Gtk2::Entry->new();
	    $gui_connections{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}={
		element => \$gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'},
		data => 'status.client.remoteHost.'.$newTableDatanames[$i],
		type => 'text' };
	} else {
	    $gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}=
		Gtk2::ComboBox->new_text;
	    $gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}->append_text('disabled');
	    $gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}->append_text('enabled');
	    $gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}->set_active(0);
	    $gui_connections{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'}={
		element => \$gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'},
		data => 'status.client.remoteHost.'.$newTableDatanames[$i],
		type => 'dropdown' };
	}
	$gui_elements{'cRHW_nHF_tB_newTable'}->
	    attach_defaults($gui_elements{'cRHW_nHF_tB_nT_userInput_'.$newTableDatanames[$i].'Input'},1,2,$i,$i+1);
    }
    $gui_elements{'cRHW_nHF_tB_addHostButton'}=Gtk2::Button->new('Add to List');

    # add the frames
    $gui_elements{'cRHW_eF_tableBox'}->pack_start($gui_elements{'cRHW_eF_tB_enabledTable'},TRUE,TRUE,4);
    $gui_elements{'cRHW_enabledFrame'}->add($gui_elements{'cRHW_eF_tableBox'});
    $gui_elements{'cRHW_mainContainer'}->add($gui_elements{'cRHW_enabledFrame'});
    $gui_elements{'cRHW_aF_tableBox'}->pack_start($gui_elements{'cRHW_aF_tB_availableTable'},TRUE,TRUE,4);
    $gui_elements{'cRHW_availableFrame'}->add($gui_elements{'cRHW_aF_tableBox'});
    $gui_elements{'cRHW_mainContainer'}->add($gui_elements{'cRHW_availableFrame'});

    $gui_elements{'cRHW_nHF_tableBox'}->pack_start($gui_elements{'cRHW_nHF_tB_newTable'},TRUE,TRUE,4);
    $gui_elements{'cRHW_nHF_tableBox'}->pack_start($gui_elements{'cRHW_nHF_tB_addHostButton'},TRUE,TRUE,4);
    $gui_elements{'cRHW_newHostFrame'}->add($gui_elements{'cRHW_nHF_tableBox'});
    $gui_elements{'cRHW_mainContainer'}->add($gui_elements{'cRHW_newHostFrame'});
    
    # connect the main window button to make the remote host window appear
    $gui_elements{'cMW_dF_tB_remoteHostButton'}->signal_connect('clicked' => sub {
	$gui_elements{'cdiskoRemoteHostWindow'}->show_all;
    });

    # make the add host button do something
    &button_background_colour(\$gui_elements{'cRHW_nHF_tB_addHostButton'},'yellow');
    $gui_elements{'cRHW_nHF_tB_addHostButton'}->signal_connect('clicked',\&add_new_host);

    # make a new window for the recorder status
    $gui_elements{'cdiskoRecordingWindow'}=Gtk2::Window->new;
    $gui_elements{'cdiskoRecordingWindow'}->signal_connect ( delete_event => sub {
	$gui_elements{'cdiskoRecordingWindow'}->hide;
	return TRUE;
    });
    $gui_elements{'cdiskoRecordingWindow'}->set_title('Recording Status');
    $gui_elements{'cMW_sB_recordingSummaryLabel'}->signal_connect('clicked', sub {
	$gui_elements{'cdiskoRecordingWindow'}->show_all;
    });
    $gui_elements{'cRW_mainContainer'}=Gtk2::VBox->new( FALSE, 5 );
    $gui_elements{'cdiskoRecordingWindow'}->add($gui_elements{'cRW_mainContainer'});
    # the settings summary frame
    $gui_elements{'cRW_recordingSettingsFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRW_recordingSettingsFrame'}->set_border_width(10);
    $gui_elements{'cRW_recordingSettingsFrame'}->set_shadow_type('out');
    $gui_elements{'cRW_recordingSettingsFrame'}->set_label('Recording Settings');
    $gui_elements{'cRW_rSF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRW_rSF_tB_settingsTable'}=Gtk2::Table->new(3,4,FALSE);
    my @settingsTableHeadings=("Experiment","Duration","Bandwidth (MHz)","# of bits");#,"Compression");#,"Bit rate (Mbps)");
    my @settingsTableDatanames=('experimentName','recordTime','bandwidth','nbits');#,'compressionChannels');#,'bitrate');
    for (my $i=0;$i<=$#settingsTableHeadings;$i++){
	my $txloc=2*$i;
	my $tyloc=0;
	while ($txloc>3){
	    $txloc-=4;
	    $tyloc++;
	}
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$settingsTableHeadings[$i].':</b>');
	$tablelabel->set_alignment(1.0,0.5);
	$gui_elements{'cRW_rSF_tB_settingsTable'}->attach_defaults($tablelabel,$txloc,$txloc+1,$tyloc,$tyloc+1);
	$gui_elements{'cRW_rSF_tB_sT_'.$settingsTableDatanames[$i].'Label'}=Gtk2::Label->new();
	$gui_connections{'cRW_rSF_tB_sT_'.$settingsTableDatanames[$i].'Label'}={
	    element => \$gui_elements{'cRW_rSF_tB_sT_'.$settingsTableDatanames[$i].'Label'},
	    data => 'status.server.recording.'.$settingsTableDatanames[$i],
	    type => 'label' };
	$gui_elements{'cRW_rSF_tB_settingsTable'}->
	    attach_defaults($gui_elements{'cRW_rSF_tB_sT_'.$settingsTableDatanames[$i].'Label'},
			    $txloc+1,$txloc+2,$tyloc,$tyloc+1);
    }
    # the disk summary frame
    $gui_elements{'cRW_outputDiskFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRW_outputDiskFrame'}->set_border_width(10);
    $gui_elements{'cRW_outputDiskFrame'}->set_shadow_type('out');
    $gui_elements{'cRW_outputDiskFrame'}->set_label('Output Disks');
    $gui_elements{'cRW_oDF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $settings{'max_simultaneous_disks'}=4;
    $gui_elements{'cRW_oDF_tB_disksTable'}=Gtk2::Table->new($settings{'max_simultaneous_disks'}+1,8,FALSE);
    my @outputDiskTableHeadings=("Recorder","Disk Name","Label","Size","Remaining","% left",,"Time Left (h:m:s)",
				 "Compression");
    my @outputDiskTableDatanames=('recorder','disk','label','size','remaining','rempercent','remtime',
				  'compressionChannels');
    for (my $i=0;$i<=$#outputDiskTableHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$outputDiskTableHeadings[$i].'</b>');
	$gui_elements{'cRW_oDF_tB_disksTable'}->attach_defaults($tablelabel,$i,$i+1,0,1);
	$gui_elements{'cRW_oDF_tB_disksTable'}->set_col_spacing($i,8);
	for (my $j=0;$j<$settings{'max_simultaneous_disks'};$j++){
	    ${$gui_elements{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j]=
		Gtk2::Label->new();
	    $gui_elements{'cRW_oDF_tB_disksTable'}->
		attach_defaults(${$gui_elements{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j],
				$i,$i+1,$j+1,$j+2);
	    if ($outputDiskTableDatanames[$i] ne 'compressionChannels'){
		${$gui_connections{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j]={
		    element => \${$gui_elements{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j],
		    data => 'status.server.recording.'.$outputDiskTableDatanames[$i].'.target'.$j,
		    type => 'label' };
	    } else {
		${$gui_connections{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j]={
		    element => \${$gui_elements{'cRW_oDF_tB_dT_'.$outputDiskTableDatanames[$i].'Label'}}[$j],
		    data => 'status.server.recording.'.($j+1).'.'.$outputDiskTableDatanames[$i],
		    type => 'label' };
	    }		
	}
    }
    # the recording summary frame
    $gui_elements{'cRW_recordingSummaryFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRW_recordingSummaryFrame'}->set_border_width(10);
    $gui_elements{'cRW_recordingSummaryFrame'}->set_shadow_type('out');
    $gui_elements{'cRW_recordingSummaryFrame'}->set_label('Recording Summary');
    $gui_elements{'cRW_rSuF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRW_rSuF_tB_summaryTable'}=Gtk2::Table->new(2,5,FALSE);
    my @recordingSummaryHeadings=("Last 1PPS","Missed 1PPS","Last BIGBUF","Last block","Last file");
    my @recordingSummaryDatanames=('lastpps','missedpps','lastbigbuf','lastblock','lastfile');
    for (my $i=0;$i<=$#recordingSummaryHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$recordingSummaryHeadings[$i].':</b>');
	$tablelabel->set_alignment(1.0,0.5);
	$gui_elements{'cRW_rSuF_tB_summaryTable'}->attach_defaults($tablelabel,0,1,$i,$i+1);
	$gui_elements{'cRW_rSuF_tB_sT_'.$recordingSummaryDatanames[$i].'Label'}=Gtk2::Label->new();
	$gui_connections{'cRW_rSuF_tB_sT_'.$recordingSummaryDatanames[$i].'Label'}={
	    element => \$gui_elements{'cRW_rSuF_tB_sT_'.$recordingSummaryDatanames[$i].'Label'},
	    data => 'status.server.recording.'.$recordingSummaryDatanames[$i],
	    type => 'label' };
	$gui_elements{'cRW_rSuF_tB_summaryTable'}->
	    attach_defaults($gui_elements{'cRW_rSuF_tB_sT_'.$recordingSummaryDatanames[$i].'Label'},
			    1,2,$i,$i+1);
    }
    # the statistics frame
    $gui_elements{'cRW_statisticsFrame'}=Gtk2::Frame->new();
    $gui_elements{'cRW_statisticsFrame'}->set_border_width(10);
    $gui_elements{'cRW_statisticsFrame'}->set_shadow_type('out');
    $gui_elements{'cRW_statisticsFrame'}->set_label('Statistics');
    $gui_elements{'cRW_sF_labelBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cRW_sF_lB_statisticsLabel'}=Gtk2::Label->new();
    $gui_connections{'cRW_sF_lB_statisticsLabel'}={
	element => \$gui_elements{'cRW_sF_lB_statisticsLabel'},
	data => 'status.server.recording.statistics',
	type => 'label' };
    $gui_elements{'cRW_sF_labelBox'}->pack_start($gui_elements{'cRW_sF_lB_statisticsLabel'},TRUE,TRUE,4);

    # add the frames
    $gui_elements{'cRW_rSF_tableBox'}->pack_start($gui_elements{'cRW_rSF_tB_settingsTable'},TRUE,TRUE,4);
    $gui_elements{'cRW_recordingSettingsFrame'}->add($gui_elements{'cRW_rSF_tableBox'});
    $gui_elements{'cRW_mainContainer'}->add($gui_elements{'cRW_recordingSettingsFrame'});
    $gui_elements{'cRW_oDF_tableBox'}->pack_start($gui_elements{'cRW_oDF_tB_disksTable'},TRUE,TRUE,4);
    $gui_elements{'cRW_outputDiskFrame'}->add($gui_elements{'cRW_oDF_tableBox'});
    $gui_elements{'cRW_mainContainer'}->add($gui_elements{'cRW_outputDiskFrame'});
    $gui_elements{'cRW_rSuF_tableBox'}->pack_start($gui_elements{'cRW_rSuF_tB_summaryTable'},TRUE,TRUE,4);
    $gui_elements{'cRW_recordingSummaryFrame'}->add($gui_elements{'cRW_rSuF_tableBox'});
    $gui_elements{'cRW_mainContainer'}->add($gui_elements{'cRW_recordingSummaryFrame'});
    $gui_elements{'cRW_statisticsFrame'}->add($gui_elements{'cRW_sF_labelBox'});
    $gui_elements{'cRW_mainContainer'}->add($gui_elements{'cRW_statisticsFrame'});

    # make a new window for the experiment queue
    $gui_elements{'cdiskoExperimentQueueWindow'}=Gtk2::Window->new;
    $gui_elements{'cdiskoExperimentQueueWindow'}->signal_connect ( delete_event => sub {
	$gui_elements{'cdiskoExperimentQueueWindow'}->hide;
	return TRUE;
    });
    $gui_elements{'cdiskoExperimentQueueWindow'}->set_title('Experiment Queue');
    $gui_elements{'cEQW_mainContainer'}=Gtk2::VBox->new( FALSE, 5 );
    $gui_elements{'cdiskoExperimentQueueWindow'}->add($gui_elements{'cEQW_mainContainer'});
    # the queue frame
    $gui_elements{'cEQW_experimentQueueFrame'}=Gtk2::Frame->new();
    $gui_elements{'cEQW_experimentQueueFrame'}->set_border_width(10);
    $gui_elements{'cEQW_experimentQueueFrame'}->set_shadow_type('out');
    $gui_elements{'cEQW_experimentQueueFrame'}->set_label('Experiment Queue');
    $gui_elements{'cEQW_eQF_tableBox'}=Gtk2::VBox->new(FALSE,5);
    $gui_elements{'cEQW_eQF_tB_queueTable'}=Gtk2::Table->new(1,3,FALSE);
    my @experimentTableHeadings=("Experiment ID","Start Time","End Time");
    for (my $i=0;$i<=$#experimentTableHeadings;$i++){
	my $tablelabel=Gtk2::Label->new();
	$tablelabel->set_markup('<b>'.$experimentTableHeadings[$i].'</b>');
	$gui_elements{'cEQW_eQF_tB_queueTable'}->attach_defaults($tablelabel,$i,$i+1,0,1);
	$gui_elements{'cEQW_eQF_tB_queueTable'}->set_col_spacing($i,10);
    }

    # add the frames
    $gui_elements{'cEQW_eQF_tableBox'}->pack_start($gui_elements{'cEQW_eQF_tB_queueTable'},TRUE,TRUE,4);
    $gui_elements{'cEQW_experimentQueueFrame'}->add($gui_elements{'cEQW_eQF_tableBox'});
    $gui_elements{'cEQW_mainContainer'}->add($gui_elements{'cEQW_experimentQueueFrame'});
    # make the current experiment label button show the queue window
    $gui_elements{'cMW_sB_currentExperimentLabel'}->signal_connect('clicked', sub {
	$gui_elements{'cdiskoExperimentQueueWindow'}->show_all;
    });
}

sub fill_settings_window {
    my ($windowref,$number)=@_;

    my $window=${$windowref};

    ${$gui_elements{'cSW_mainContainer'}}[$number]=Gtk2::VBox->new ( FALSE, 5 );
    $window->add(${$gui_elements{'cSW_mainContainer'}}[$number]);
    ${$gui_elements{'cSW_settingsTable'}}[$number]=Gtk2::Table->new(9,7,FALSE);
    ${$gui_elements{'cSW_settingsTable'}}[$number]->set_col_spacings(5);
    ${$gui_elements{'cSW_mainContainer'}}[$number]->pack_start(${$gui_elements{'cSW_settingsTable'}}[$number],TRUE,TRUE,4);
    
    my $servervaluelabel=Gtk2::Label->new();
    $servervaluelabel->set_markup('<b>Server Value</b>');
    ${$gui_elements{'cSW_settingsTable'}}[$number]->attach_defaults($servervaluelabel,1,2,0,1);
    my @rowlabels=("Profile Name","Experiment Name","Recording Time","Start Time","Bandwidth (MHz)","Channels",
		   "Disk Selection","Rounded Start?","Mark 5B Recording?");
    for (my $i=0;$i<=$#rowlabels;$i++){
	my $rowlabel=Gtk2::Label->new();
	$rowlabel->set_markup('<b>'.$rowlabels[$i].':</b>');
	$rowlabel->set_alignment(1.0,0.5);
	${$gui_elements{'cSW_settingsTable'}}[$number]->attach_defaults($rowlabel,0,1,$i+1,$i+2);
    }
    # make the server value labels
    # the name of the profile
    ${$gui_elements{'cSW_sT_profileNameLabel'}}[$number]=Gtk2::Label->
	new(${$status{'settings_window_profileName'}}[$number]);
    ${$gui_elements{'cSW_sT_profileNameLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_profileNameLabel'}}[$number],1,2,1,2);
    # the name of the experiment
    ${$gui_elements{'cSW_sT_serverValue_experimentNameLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_experimentNameLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_experimentNameLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_experimentNameLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.experimentName',
	type => 'label'};
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_experimentNameLabel'}}[$number],1,2,2,3);
    # the recording time
    ${$gui_elements{'cSW_sT_serverValue_recordingTimeLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_recordingTimeLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_recordingTimeLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_recordingTimeLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordTime',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_recordingTimeLabel'}}[$number],1,2,3,4);
    # the start time
    ${$gui_elements{'cSW_sT_serverValue_recordingStartTimeLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_recordingStartTimeLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_recordingStartTimeLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_recordingStartTimeLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTime',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_recordingStartTimeLabel'}}[$number],1,2,4,5);
    # the bandwidth
    ${$gui_elements{'cSW_sT_serverValue_recordingBandwidthLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_recordingBandwidthLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_recordingBandwidthLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_recordingBandwidthLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.bandwidth',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_recordingBandwidthLabel'}}[$number],1,2,5,6);
    # the compression mode
    ${$gui_elements{'cSW_sT_serverValue_compressionModeLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_compressionModeLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_compressionModeLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_compressionModeLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.compressionMode',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_compressionModeLabel'}}[$number],1,2,6,7);
    # the disk to use
    ${$gui_elements{'cSW_sT_serverValue_recordingDiskLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_recordingDiskLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_recordingDiskLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_recordingDiskLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.selectedDisk',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_recordingDiskLabel'}}[$number],1,2,7,8);
    # auto round start status
    ${$gui_elements{'cSW_sT_serverValue_autoRoundStartLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_autoRoundStartLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_autoRoundStartLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_autoRoundStartLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.autoRoundStart',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_autoRoundStartLabel'}}[$number],1,2,8,9);
    # Mark 5B recording status
    ${$gui_elements{'cSW_sT_serverValue_mark5BLabel'}}[$number]=Gtk2::Label->new();
    ${$gui_elements{'cSW_sT_serverValue_mark5BLabel'}}[$number]->set_alignment(0.0,0.5);
    ${$gui_connections{'cSW_sT_serverValue_mark5BLabel'}}[$number]={
	element => \${$gui_elements{'cSW_sT_serverValue_mark5BLabel'}}[$number],
	data => 'status.server.settings.'.${$status{'settings_window_profileName'}}[$number].'.mark5B',
	type => 'label' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_serverValue_mark5BLabel'}}[$number],1,2,9,10);

    # make the user input fields
    # do we include this profile in threaded recording?
    if (${$status{'settings_window_profileName'}}[$number] ne 'Default'){
	${$gui_elements{'cSW_sT_userInput_includeThreaded'}}[$number]=Gtk2::ToggleButton->
	    new_with_label('Not included in threaded recording');
	${$gui_connections{'cSW_sT_userInput_includeThreaded'}}[$number]={
	    element => \${$gui_elements{'cSW_sT_userInput_includeThreaded'}}[$number],
	    data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.includeThreaded',
	    type => 'checkbutton' };
	${$gui_elements{'cSW_settingsTable'}}[$number]->
	    attach_defaults(${$gui_elements{'cSW_sT_userInput_includeThreaded'}}[$number],2,3,1,2);
	${$gui_elements{'cSW_sT_userInput_includeThreaded'}}[$number]->
	    signal_connect('toggled',\&recording_button_state);
    }
    # the experiment name
    ${$gui_elements{'cSW_sT_userInput_experimentNameInput'}}[$number]=Gtk2::Entry->new();
    ${$gui_connections{'cSW_sT_userInput_experimentNameInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_experimentNameInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.experimentName',
	type => 'text' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_experimentNameInput'}}[$number],2,3,2,3);
    # the recording time
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]=Gtk2::HBox->new( FALSE, 5 );
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeHoursInput'}}[$number]=Gtk2::Entry->new_with_max_length(3);
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeHoursInput'}}[$number]->set_width_chars(3);
    ${$gui_connections{'cSW_sT_rTB_userInput_recordTimeHoursInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rTB_userInput_recordTimeHoursInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordTimeHours',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rTB_userInput_recordTimeHoursInput'}}[$number],FALSE,FALSE,4);
    my $unitslabel=Gtk2::Label->new('h');
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->pack_start($unitslabel,FALSE,FALSE,4);
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeMinutesInput'}}[$number]=Gtk2::Entry->new_with_max_length(3);
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeMinutesInput'}}[$number]->set_width_chars(3);
    ${$gui_connections{'cSW_sT_rTB_userInput_recordTimeMinutesInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rTB_userInput_recordTimeMinutesInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordTimeMinutes',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rTB_userInput_recordTimeMinutesInput'}}[$number],FALSE,FALSE,4);
    $unitslabel=Gtk2::Label->new('m');
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->pack_start($unitslabel,FALSE,FALSE,4);
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeSecondsInput'}}[$number]=Gtk2::Entry->new_with_max_length(3);
    ${$gui_elements{'cSW_sT_rTB_userInput_recordTimeSecondsInput'}}[$number]->set_width_chars(3);
    ${$gui_connections{'cSW_sT_rTB_userInput_recordTimeSecondsInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rTB_userInput_recordTimeSecondsInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordTimeSeconds',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rTB_userInput_recordTimeSecondsInput'}}[$number],FALSE,FALSE,4);
    $unitslabel=Gtk2::Label->new('s');
    ${$gui_elements{'cSW_sT_recordTimeBox'}}[$number]->pack_start($unitslabel,FALSE,FALSE,4);
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_recordTimeBox'}}[$number],2,3,3,4);
    # the recording start time
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]=Gtk2::HBox->new( FALSE, 5 );
    $unitslabel=Gtk2::Label->new('Year:');
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->pack_start($unitslabel,FALSE,FALSE,0);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeYearInput'}}[$number]=Gtk2::Entry->new_with_max_length(4);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeYearInput'}}[$number]->set_width_chars(4);
    ${$gui_connections{'cSW_sT_rSTB_userInput_recordStartTimeYearInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeYearInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeYear',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeYearInput'}}[$number],FALSE,FALSE,0);
    $unitslabel=Gtk2::Label->new('DOY:');
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->pack_start($unitslabel,FALSE,FALSE,0);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeDOYInput'}}[$number]=Gtk2::Entry->new_with_max_length(3);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeDOYInput'}}[$number]->set_width_chars(3);
    ${$gui_connections{'cSW_sT_rSTB_userInput_recordStartTimeDOYInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeDOYInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeDOY',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeDOYInput'}}[$number],FALSE,FALSE,0);

    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeHourInput'}}[$number]=Gtk2::Entry->new_with_max_length(2);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeHourInput'}}[$number]->set_width_chars(2);
    ${$gui_connections{'cSW_sT_rSTB_userInput_recordStartTimeHourInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeHourInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeHour',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeHourInput'}}[$number],FALSE,FALSE,0);
    my $colonlabel=Gtk2::Label->new(':');
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->pack_start($colonlabel,FALSE,FALSE,0);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeMinuteInput'}}[$number]=Gtk2::Entry->new_with_max_length(2);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeMinuteInput'}}[$number]->set_width_chars(2);
    ${$gui_connections{'cSW_sT_rSTB_userInput_recordStartTimeMinuteInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeMinuteInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeMinute',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeMinuteInput'}}[$number],FALSE,FALSE,0);
    $colonlabel=Gtk2::Label->new(':');
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->pack_start($colonlabel,FALSE,FALSE,0);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeSecondInput'}}[$number]=Gtk2::Entry->new_with_max_length(2);
    ${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeSecondInput'}}[$number]->set_width_chars(2);
    ${$gui_connections{'cSW_sT_rSTB_userInput_recordStartTimeSecondInput'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeSecondInput'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeSecond',
	type => 'text' };
    ${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTB_userInput_recordStartTimeSecondInput'}}[$number],FALSE,FALSE,0);
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_recordStartTimeBox'}}[$number],2,3,4,5);
    ${$gui_elements{'cSW_sT_recordStartTimeFunctionsBox'}}[$number]=Gtk2::HBox->new( FALSE, 5 );
    ${$gui_elements{'cSW_sT_rSTFB_timeSetButton'}}[$number]=Gtk2::Button->new('Now + 1m');
    ${$gui_elements{'cSW_sT_recordStartTimeFunctionsBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTFB_timeSetButton'}}[$number],FALSE,FALSE,4);
    ${$gui_elements{'cSW_sT_rSTFB_timeSetButton'}}[$number]->
	signal_connect('clicked',\&set_start_time_settings,${$status{'settings_window_profileName'}}[$number]);
    ${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]=Gtk2::ToggleButton->new_with_label('Disabled');
    ${$gui_connections{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]={
	element => \${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.recordStartTimeEnabled',
	type => 'checkbutton' };
    ${$gui_elements{'cSW_sT_recordStartTimeFunctionsBox'}}[$number]->
	pack_start(${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number],FALSE,FALSE,1);
    ${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]->signal_connect('toggled', sub {
	if (${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]->get_active){
	    ${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]->set_label('Enabled');
	} else {
	    ${$gui_elements{'cSW_sT_rSTFB_timeEnabledButton'}}[$number]->set_label('Disabled');
	}
    });

    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_recordStartTimeFunctionsBox'}}[$number],3,4,4,5);
    # the bandwidth
    @{$settings{'available_bandwidths'}}=(1,2,4,8,16,32,64);
    ${$gui_elements{'cSW_sT_userInput_bandwidthSelector'}}[$number]=Gtk2::ComboBox->new_text;
    for (my $i=0;$i<=$#{$settings{'available_bandwidths'}};$i++){
	${$gui_elements{'cSW_sT_userInput_bandwidthSelector'}}[$number]->
	    append_text(${$settings{'available_bandwidths'}}[$i]);
    }
    ${$gui_connections{'cSW_sT_userInput_bandwidthSelector'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_bandwidthSelector'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.bandwidth',
	type => 'dropdown' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_bandwidthSelector'}}[$number],2,3,5,6);
    # the compression settings
    ${$gui_elements{'cSW_sT_userInput_channelSelector'}}[$number]=Gtk2::ComboBox->new_text;
    ${$gui_connections{'cSW_sT_userInput_channelSelector'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_channelSelector'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.compressionMode',
	type => 'dropdown' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_channelSelector'}}[$number],2,3,6,7);
    ${$gui_elements{'cSW_sT_userInput_huygensCableButton'}}[$number]=Gtk2::ToggleButton->new_with_label('No Huygens Cable');
    ${$gui_connections{'cSW_sT_userInput_huygensCableButton'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_huygensCableButton'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.huygens',
	type => 'checkbutton' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_huygensCableButton'}}[$number],3,4,6,7);
    ${$status{'n_compression_options'}}[$number]=0;
    ${$gui_elements{'signalConnection_huygensButton'}}[$number]=
	${$gui_elements{'cSW_sT_userInput_huygensCableButton'}}[$number]->
	signal_connect('toggled',\&update_compression_options);
    ${gui_connections{'signalConnection_huygensButton'}}[$number]={
	element => \${$gui_elements{'signalConnection_huygensButton'}}[$number],
	data => 'status.client.state.'.${$status{'settings_window_profileName'}}[$number].'.huygens' };
    ${$gui_elements{'cSW_sT_userInput_bandwidthSelector'}}[$number]->
	signal_connect('changed',\&update_compression_options);
    # the disk selection
    ${$gui_elements{'cSW_sT_userInput_diskSelector'}}[$number]=Gtk2::ComboBox->new_text;
    ${$gui_connections{'cSW_sT_userInput_diskSelector'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_diskSelector'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.selectedDisk',
	type => 'dropdown' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_diskSelector'}}[$number],2,3,7,8);
    ${$status{'n_disk_options'}}[$number]=0;
    # the rounded start checkbox
    ${$gui_elements{'cSW_sT_userInput_roundStartSelector'}}[$number]=Gtk2::ComboBox->new_text;
    ${$gui_elements{'cSW_sT_userInput_roundStartSelector'}}[$number]->append_text('enabled');
    ${$gui_elements{'cSW_sT_userInput_roundStartSelector'}}[$number]->append_text('disabled');
    ${$gui_connections{'cSW_sT_userInput_roundStartSelector'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_roundStartSelector'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.autoRoundStart',
	type => 'dropdown' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_roundStartSelector'}}[$number],2,3,8,9);
    # Mark 5B recording
    ${$gui_elements{'cSW_sT_userInput_mark5BSelector'}}[$number]=Gtk2::ComboBox->new_text;
    ${$gui_elements{'cSW_sT_userInput_mark5BSelector'}}[$number]->append_text('enabled');
    ${$gui_elements{'cSW_sT_userInput_mark5BSelector'}}[$number]->append_text('disabled');
    ${$gui_connections{'cSW_sT_userInput_mark5BSelector'}}[$number]={
	element => \${$gui_elements{'cSW_sT_userInput_mark5BSelector'}}[$number],
	data => 'status.client.settings.'.${$status{'settings_window_profileName'}}[$number].'.mark5B',
	type => 'dropdown' };
    ${$gui_elements{'cSW_settingsTable'}}[$number]->
	attach_defaults(${$gui_elements{'cSW_sT_userInput_mark5BSelector'}}[$number],2,3,9,10);

    # make a submit button that updates the server with our settings
    ${$gui_elements{'cSW_submitSettingsButton'}}[$number]=Gtk2::Button->new('Submit');
    ${$gui_elements{'cSW_mainContainer'}}[$number]->
	pack_start(${$gui_elements{'cSW_submitSettingsButton'}}[$number],TRUE,TRUE,4);
    # make it a yellow button
    &button_background_colour(\${$gui_elements{'cSW_submitSettingsButton'}}[$number],'yellow');
    ${$gui_elements{'cSW_submitSettingsButton'}}[$number]->
	signal_connect('clicked',\&submit_settings,${$status{'settings_window_profileName'}}[$number]);

    if (${$status{'settings_window_profileName'}}[$number] ne 'Default'){
	# make a button to insert/remove the profile from the experiment queue
	${$gui_elements{'cSW_experimentProfileButton'}}[$number]=Gtk2::Button->new('Add to Experiment Queue');
	${$gui_connections{'cSW_experimentProfileButton'}}[$number]={
	    element => \${$gui_elements{'cSW_experimentProfileButton'}}[$number],
	    data => 'status.server.experiment.'.${$status{'settings_window_profileName'}}[$number],
	    type => 'button' };
	${$gui_elements{'cSW_mainContainer'}}[$number]->
	    pack_start(${$gui_elements{'cSW_experimentProfileButton'}}[$number],TRUE,TRUE,0);
	${$gui_elements{'cSW_experimentProfileButton'}}[$number]->
	    signal_connect('clicked',\&experimentprofiles,${$status{'settings_window_profileName'}}[$number]);
	&button_background_colour(\${$gui_elements{'cSW_experimentProfileButton'}}[$number],'white');
	# make a "remove profile" button
	${$gui_elements{'cSW_removeProfileButton'}}[$number]=Gtk2::Button->new('Remove Profile');
	${$gui_elements{'cSW_mainContainer'}}[$number]->
	    pack_start(${$gui_elements{'cSW_removeProfileButton'}}[$number],TRUE,TRUE,0);
	# make it a red button
	&button_background_colour(\${$gui_elements{'cSW_removeProfileButton'}}[$number],'red');
	${$gui_elements{'cSW_removeProfileButton'}}[$number]->
	    signal_connect('clicked',\&remove_profile,${$status{'settings_window_profileName'}}[$number]);
    }
}

sub experimentprofiles {
    my ($buttonref,$profile)=@_;

    my $btnlabel=&get_value('status.server.experiment.'.$profile);
    if ($btnlabel=~/^Add/){
	my $comm_result=&server_comms('cmnd','rectarget-makeexp:'.$profile);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to put recording profile ".$profile." onto experiment queue:\n".
				 $status{'communication_error'},'error');
	}
    } elsif ($btnlabel=~/^Remove/){
	my $comm_result=&server_comms('cmnd','experiment-unload:'.$profile);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to remove recording profile ".$profile." from experiment queue:\n".
				 $status{'communication_error'},'error');
	}
    }
}

sub add_profile {
    
    # the name the user wants for the new profile
    my $profile=&get_value('status.client.newProfileName');
    if ($profile){
	my $comm_result=&server_comms('cmnd','rectarget-make:'.$profile);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to make recording profile ".$profile.":\n".
				 $status{'communication_error'},'error');
	}
    }
    &set_value('status.client.newProfileName','');
}

sub remove_profile {
    my ($buttonref,$profile)=@_;

    if ($profile){
	my $comm_result=&server_comms('cmnd','rectarget-rem:'.$profile);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to remove recording profile ".$profile.":\n".
				 $status{'communication_error'},'error');
	}
    }
}

sub add_new_host {
    
    # get all the required information
    my $newhost_commonname=&get_value('status.client.remoteHost.nickname');
    my $newhost_hostname=&get_value('status.client.remoteHost.hostname');
    my $newhost_tcpport=&get_value('status.client.remoteHost.tcpport');
    my $newhost_tcpwindowsize=&get_value('status.client.remoteHost.tcpwindowsize');
    my $newhost_evlbimode=&get_value('status.client.remoteHost.evlbienabled');
    # and some optional information
    my $newhost_udpsize=&get_value('status.client.remoteHost.udpsize');
    if (!$newhost_udpsize){
	$newhost_udpsize=0;
    }
    
    if ($newhost_commonname && $newhost_hostname && $newhost_tcpport && $newhost_tcpwindowsize &&
	$newhost_evlbimode){
	# find the next available host
	my $nextavailable;
	for (my $i=1;$i<=20;$i++){
	    if (!${$settings{'remote_commonname'}}[$i]){
		$nextavailable=$i;
		last;
	    }
	}
	${$settings{'remote_commonname'}}[$nextavailable]=$newhost_commonname;
	${$settings{'remote_hostname'}}[$nextavailable]=$newhost_hostname;
	${$settings{'remote_datacommunicationport'}}[$nextavailable]=$newhost_tcpport;
	${$settings{'remote_tcpwindowsize'}}[$nextavailable]=$newhost_tcpwindowsize;
	${$settings{'remote_udpenabled'}}[$nextavailable]=$newhost_udpsize;
	my $evlbiflag=0;
	if ($newhost_evlbimode eq 'enabled'){
	    $evlbiflag=1;
	}
	${$settings{'remote_evlbimode'}}[$nextavailable]=$evlbiflag;
	${$settings{'remote_registered'}}[$nextavailable]=0;

	# clear the input fields
	&set_value('status.client.remoteHost.nickname','');
	&set_value('status.client.remoteHost.hostname','');
	&set_value('status.client.remoteHost.tcpport','');
	&set_value('status.client.remoteHost.tcpwindowsize','');
	&set_value('status.client.remoteHost.udpsize','');
    }

    &update_remote_hosts();
}

sub set_start_time_settings {
    my ($buttonref,$profile)=@_;

    # get the time
    my $mjd=now2mjd();
    $mjd+=60/86400; # add 1 minute
    my $dayno;
    my ($day,$month,$year,$ut)=mjd2cal($mjd);
    ($dayno,$year,$ut)=mjd2dayno($mjd);
    my $str=turn2str($ut,'H',0);
    while (length($str)<8){
	$str='0'.$str;
    }
    my @utels=split(/\:/,$str);
    
    # set the GUI
    &set_value('status.client.settings.'.$profile.'.recordStartTimeYear',$year);
    &set_value('status.client.settings.'.$profile.'.recordStartTimeDOY',$dayno);
    &set_value('status.client.settings.'.$profile.'.recordStartTimeHour',$utels[0]);
    &set_value('status.client.settings.'.$profile.'.recordStartTimeMinute',$utels[1]);
    &set_value('status.client.settings.'.$profile.'.recordStartTimeSecond',$utels[2]);

}

sub submit_settings {
    my ($buttonref,$profile)=@_;

    my $profileprefix='';
    if ($profile ne 'Default'){
	$profileprefix='~'.$profile.'~';
    }
    
    # do the data submission
    # the experiment name
    my $new_experimentname=&get_value('status.client.settings.'.$profile.'.experimentName');
    my $current_experimentname=&get_value('status.server.settings.'.$profile.'.experimentName');
    if (($new_experimentname ne '')&&($new_experimentname ne $current_experimentname)){
	my $new_filename=$new_experimentname.'_'.${$settings{'antenna_names'}}{$localsettings->{'antenna'}};
	my $comm_result=&server_comms('data',$profileprefix.'directory_name='.$new_experimentname);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to set experiment name to ".$new_experimentname.":\n".
				 $status{'communication_error'},'error');
	} else {
	    $comm_result=&server_comms('data',$profileprefix.'filename_prefix='.$new_filename);
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to set experiment name to ".$new_experimentname.":\n".
				     $status{'communication_error'},'error');
	    }
	}
    }
    # the recording time
    my $new_rectime_hours=&get_value('status.client.settings.'.$profile.'.recordTimeHours');
    my $new_rectime_minutes=&get_value('status.client.settings.'.$profile.'.recordTimeMinutes');
    my $new_rectime_seconds=&get_value('status.client.settings.'.$profile.'.recordTimeSeconds');
    my $new_rectime='';
    if ($new_rectime_hours && $new_rectime_minutes && $new_rectime_seconds){
	if ($new_rectime_seconds!=0){
	    # we'll need to make a time in seconds
	    $new_rectime=(($new_rectime_hours*3600)+($new_rectime_minutes*60)+$new_rectime_seconds).'s';
	} elsif ($new_rectime_minutes!=0){
	    # we'll need to make a time in minutes
	    $new_rectime=(($new_rectime_hours*60)+$new_rectime_minutes).'m';
	} else {
	    # just make it in hours
	    $new_rectime=$new_rectime_hours.'h';
	}
    } elsif ($new_rectime_seconds){
	my $rectimevalue=$new_rectime_seconds;
	if ($new_rectime_hours){
	    $rectimevalue+=3600*$new_rectime_hours;
	}
	if ($new_rectime_minutes){
	    $rectimevalue+=60*$new_rectime_minutes;
	}
	$new_rectime=$rectimevalue.'s';
    } elsif ($new_rectime_minutes){
	my $rectimevalue=$new_rectime_minutes;
	if ($new_rectime_hours){
	    $rectimevalue+=60*$new_rectime_hours;
	}
	$new_rectime=$rectimevalue.'m';
    } elsif ($new_rectime_hours){
	$new_rectime=$new_rectime_hours.'h';
    }
    my $current_rectime=&get_value('status.server.settings.'.$profile.'.recordTime');
    if (($new_rectime)&&($new_rectime ne '')){
	my $comm_result=&server_comms('data',$profileprefix.'record_time='.$new_rectime);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to set recording time to ".$new_rectime.":\n".
				 $status{'communication_error'},'error');
	}
    }
    # the recording start time
    my $new_rectime_enabled=&get_value('status.client.settings.'.$profile.'.recordStartTimeEnabled');
    my $current_rectime_enabled_indication=&get_value('status.server.settings.'.$profile.'.recordStartTime');
    my $current_rectime_enabled=TRUE;
    if ($current_rectime_enabled_indication eq 'not set'){
	$current_rectime_enabled=FALSE;
    }
    if (($new_rectime_enabled!=$current_rectime_enabled)||($new_rectime_enabled==TRUE)){
	if ($new_rectime_enabled==TRUE){
	    # we set the time regardless if the user has selected to do so
	    # check we have a usable start time
	    my $new_rectime_year=&get_value('status.client.settings.'.$profile.'.recordStartTimeYear');
	    my $new_rectime_doy=&get_value('status.client.settings.'.$profile.'.recordStartTimeDOY');
	    my $new_rectime_hour=&get_value('status.client.settings.'.$profile.'.recordStartTimeHour');
	    my $new_rectime_minute=&get_value('status.client.settings.'.$profile.'.recordStartTimeMinute');
	    my $new_rectime_second=&get_value('status.client.settings.'.$profile.'.recordStartTimeSecond');
	    if ($new_rectime_year && $new_rectime_doy && $new_rectime_hour && $new_rectime_minute &&
		$new_rectime_second){
		my $mjd=dayno2mjd($new_rectime_doy,$new_rectime_year,0);
		my ($s_day,$s_month,$s_year,$s_ut)=mjd2cal($mjd);
		my $s_date=sprintf("%4d%02d%02d",$s_year,$s_month,$s_day);
		my $s_time=sprintf("%02d%02d%02d",$new_rectime_hour,$new_rectime_minute,$new_rectime_second);
		my $comm_result=&server_comms('data',$profileprefix.'record_start_date='.$s_date);
		if (!&success($comm_result)){
		    &print2messageBuffer("Unable to set the recording start date to ".$s_date.":\n".
					 $status{'communication_error'},'error');
		} else {
		    $comm_result=&server_comms('data',$profileprefix.'record_start_time='.$s_time);
		    if (!&success($comm_result)){
			&print2messageBuffer("Unable to set the recording start time to ".$s_time.":\n".
					     $status{'communication_error'},'error');
		    }
		}
	    }
	} elsif ($new_rectime_enabled==FALSE){
	    # we need to reset the starting times
	    my $comm_result=&server_comms('data',$profileprefix.'reset=record_start_date');
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to enable immediate recording start:\n".
				     $status{'communication_error'},'error');
	    } else {
		$comm_result=&server_comms('data',$profileprefix.'reset=record_start_time');
		if (!&success($comm_result)){
		    &print2messageBuffer("Unable to enable immediate recording start:\n".
					 $status{'communication_error'},'error');
		}
	    }
	}
    }
    # the bandwidth
    my $new_bandwidth=&get_value('status.client.settings.'.$profile.'.bandwidth');
    my $current_bandwidth=&get_value('status.server.settings.'.$profile.'.bandwidth');
    if (($new_bandwidth)&&($new_bandwidth!=$current_bandwidth)){
	my $comm_result=&server_comms('data',$profileprefix.'bandwidth='.$new_bandwidth);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to set bandwidth to ".$new_bandwidth." MHz:\n".
				 $status{'communication_error'},'error');
	}
    }
    # the compression settings
    my $new_compression_modename=&get_value('status.client.settings.'.$profile.'.compressionMode');
    my $current_compression_modename=&get_value('status.server.settings.'.$profile.'.compressionMode');
    if (($new_compression_modename)&&($new_compression_modename ne $current_compression_modename)){
	my $huygens=&get_value('status.client.settings.'.$profile.'.huygens');
	my $server_bandwidth=&get_value('status.server.settings.'.$profile.'.bandwidth');
	my $user_bandwidth=&get_value('status.client.settings.'.$profile.'.bandwidth');
	# we use the user bandwidth unless it hasn't been set
	my $bandwidth;
	if (!$user_bandwidth){
	    $bandwidth=$server_bandwidth;
	} else {
	    $bandwidth=$user_bandwidth;
	}
	for (my $i=0;$i<=$#{$settings{'compression_modes'}};$i++){
	    if ((($huygens==${$settings{'compression_modes'}}[$i]->{'huygens'})||($huygens==TRUE))&&
		(($bandwidth==${$settings{'compression_modes'}}[$i]->{'bandwidth'})||
		 (($bandwidth<16)&&(${$settings{'compression_modes'}}[$i]->{'bandwidth'}==16)))&&
		($new_compression_modename eq ${$settings{'compression_modes'}}[$i]->{'mode'})){
		my $nbits=${$settings{'compression_modes'}}[$i]->{'nbits'};
		my $vsibmode;
		if ($nbits==8){
		    $vsibmode=3;
		} elsif ($nbits==16){
		    $vsibmode=2;
		}
		my $channels=${$settings{'compression_modes'}}[$i]->{'compression'};
		my $comm_result=&server_comms('data',$profileprefix.'vsib_mode='.$vsibmode);
		if (!&success($comm_result)){
		    &print2messageBuffer("Unable to set VSIB mode to ".$vsibmode.":\n".
					 $status{'communication_error'},'error');
		} else {
		    $comm_result=&server_comms('data',$profileprefix.'compression='.$channels);
		    if (!&success($comm_result)){
			&print2messageBuffer("Unable to set channels to ".$channels.":\n".
					     $status{'communication_error'},'error');
		    }
		}
		last;
	    }
	}
    }
    # the disk selection
    my $new_disk_selection=&get_value('status.client.settings.'.$profile.'.selectedDisk');
    if ($new_disk_selection){
	my $diskselect_option='off';
	if ($new_disk_selection eq 'any available disk'){
	    $diskselect_option='on_any';
	} elsif ($new_disk_selection eq 'any local disk'){
	    $diskselect_option='on_local';
	} elsif ($new_disk_selection eq 'any remote disk'){
	    $diskselect_option='on_remote';
	}
	# set the disk selection criteria
	my $comm_result=&server_comms('data',$profileprefix.'diskselection='.$diskselect_option);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to set disk selection mode to ".$diskselect_option.":\n".
				 $status{'communication_error'},'error');
	}
	if ($diskselect_option eq 'off'){
	    # select the disk in the selection box
	    # remove 'local:' if the string contains it
	    if ($new_disk_selection=~/^local\:/){
		$new_disk_selection=~s/^local\://;
	    }
	    $comm_result=&server_comms('data',$profileprefix.'recordingdisk='.$new_disk_selection);
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to set recording disk to ".$new_disk_selection.":\n".
				     $status{'communication_error'},'error');
	    }
	}   
    }
    # auto round starting
    my $new_autoroundmode=&get_value('status.client.settings.'.$profile.'.autoRoundStart');
    my $current_autoroundmode=&get_value('status.server.settings.'.$profile.'autoRoundStart');
    if (($new_autoroundmode)&&($new_autoroundmode ne $current_autoroundmode)){
	my $action=$new_autoroundmode;
	if ($new_autoroundmode eq 'enabled'){
	    $new_autoroundmode='on';
	} elsif ($new_autoroundmode eq 'disabled'){
	    $new_autoroundmode='off';
	}
	my $comm_result=&server_comms('data',$profileprefix.'round_start='.$new_autoroundmode);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to ".$action." auto rounded start time:\n".
				 $status{'communication_error'},'error');
	}
    }
    # Mark 5B recording
    my $new_mark5b=&get_value('status.client.settings.'.$profile.'.mark5B');
    my $current_mark5b=&get_value('status.server.settings.'.$profile.'.mark5B');
    if (($new_mark5b)&&($new_mark5b ne $current_mark5b)){
	my $action=$new_mark5b;
	if ($new_mark5b eq 'enabled'){
	    $new_mark5b='on';
	} elsif ($new_mark5b eq 'disabled'){
	    $new_mark5b='off';
	}
	my $comm_result=&server_comms('data',$profileprefix.'mark5b='.$new_mark5b);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to ".$action.' Mark 5B recording:\n'.
				 $status{'communication_error'},'error');
	}
    }
}

sub get_reference {
    my ($dataname)=@_;

    foreach my $key ( keys %gui_connections ) {
	if (ref($gui_connections{$key}) eq 'ARRAY'){
	    my @connection_array=@{$gui_connections{$key}};
	    for (my $i=0;$i<=$#connection_array;$i++){
		if (!$connection_array[$i]){
		    next;
		}
		my %connection_hash=%{$connection_array[$i]};
		if ($connection_hash{'data'} eq $dataname){
		    return \%connection_hash;
		}
	    }
	} elsif (ref($gui_connections{$key}) eq 'HASH'){
	    my %connection_hash=%{$gui_connections{$key}};
	    if ($connection_hash{'data'} eq $dataname){
		return \%connection_hash;
	    }
	}
    }
    return undef;
}

sub get_element_reference {
    my ($dataname)=@_;

    my $hashref=&get_reference($dataname);
    if ($hashref){
	return ${$hashref->{'element'}};
    }
    return undef;
}

sub get_value {
    my ($dataname)=@_;

    my $hashref=&get_reference($dataname);
    if (!$hashref){
	return '';
    }
    if ($hashref->{'type'} eq 'text'){
	return ${$hashref->{'element'}}->get_text;
    } elsif ($hashref->{'type'} eq 'dropdown'){
	return ${$hashref->{'element'}}->get_active_text;
    } elsif ($hashref->{'type'} eq 'label'){
	return ${$hashref->{'element'}}->get_text;
    } elsif ($hashref->{'type'} eq 'checkbutton'){
	return ${$hashref->{'element'}}->get_active;
    } elsif ($hashref->{'type'} eq 'button'){
	return ${$hashref->{'element'}}->get_label;
    }
    return '';
}

sub set_value {
    my ($dataname,$newval)=@_;

    my $hashref=&get_reference($dataname);
    if (!$hashref){
	return;
    }
    if (!$hashref->{'element'}){
	return;
    }
    if (!$newval){
	$newval='';
    }

    if (!$hashref->{'type'}){
	${$hashref->{'element'}}->set_markup($newval);
    } elsif ($hashref->{'type'} eq 'text'){
	${$hashref->{'element'}}->set_text($newval);
    } elsif ($hashref->{'type'} eq 'button'){
	${$hashref->{'element'}}->set_label($newval);
    } elsif ($hashref->{'type'} eq 'dropdown'){
#	return ${$hashref->{'element'}}->get_active_text;
    } elsif ($hashref->{'type'} eq 'label'){
	${$hashref->{'element'}}->set_markup($newval);
    } elsif ($hashref->{'type'} eq 'checkbutton'){
#	return ${$hashref->{'element'}}->get_active;
    }
    return;
}

sub get_log_timestr {
    my $mjd = now2mjd();
    my $dayno;
    my ($day, $month, $year, $ut) = mjd2cal($mjd);
    ($dayno, $year, $ut) = mjd2dayno($mjd);
    my $str = turn2str($ut, 'H', 0);
    while (length($str) < 8) {
	$str = "0".$str;
    }
    my $ut_str = sprintf ("%d.%03d.%s",$year,$dayno,$str);
    return ($ut_str);
}

sub print2messageBuffer {
    my $text=shift;
    my $state=shift;

    if (!$state){
	$state='normal';
    }

    my $time=get_log_timestr();
    my @splittext=split(/\n/,$text);

    for (my $i=0;$i<=$#splittext;$i++){
	my $first_end_iter=$gui_elements{'cMW_mF_messagesBuffer'}->get_end_iter;
	
	my $inserttext=$time.":   ".$splittext[$i]."\n";
	if (($state)&&($gui_elements{'cMW_mF_mB_'.$state.'Tag'})){
	    $gui_elements{'cMW_mF_messagesBuffer'}->insert_with_tags($first_end_iter,$inserttext,
								     $gui_elements{'cMW_mF_mB_'.$state.'Tag'});
	} else {
	    $gui_elements{'cMW_mF_messagesBuffer'}->insert($first_end_iter,$inserttext);
	}
    }
}

sub query_server {
    
    # This routine is called every few seconds to grab the latest information
    # from the recorder server and then update the GUI with the info

    my @info_commands = ('status-server','status-record','status-settings',
			 'status-remotehosts','status-recsettings',
			 'status-targets','status-experiment');
    
    # get the latest info
    my $latest_info='';
    for (my $i=0;$i<=$#info_commands;$i++){
	$latest_info.="\n".$info_commands[$i];
	for (my $j=1;$j<=$settings{'n_retries'};$j++){
	    my $comm_result=&server_comms('cmnd',$info_commands[$i]);
	    if ($comm_result eq "Can't connect to socket"){
		# can't connect to the server
		if ($j==$settings{'n_retries'}){
		    $status{'server.time.uptime'}='<span background=\'yellow\' '.
			'foreground=\'red\'>DOWN</span>';
		}
	    } elsif ($comm_result!~/\<fail\>/){
		$latest_info.="\n".$comm_result;
		last;
	    }
	}
    }
#    print $latest_info."\n";
    $status{'comm_result'}=$latest_info;

    # break up the comms result into its parts
    &interpret_status();

    # update the GUI
    &update_gui();

    # y'all come back now ya hear
    my $intervalHandle=Glib::Timeout->add($settings{'queryInterval'}*1000,
					  \&query_server);
    return;
}

sub update_compression_options {
    for (my $i=0;$i<$status{'number_settings_windows'};$i++){
	my $profile=${$status{'settings_window_profileName'}}[$i];
	my $huygens=&get_value('status.client.settings.'.$profile.'.huygens');
	# update the button label
	my $btnref=&get_element_reference('status.client.settings.'.$profile.'.huygens');
	if ($huygens){
	    $btnref->set_label('Huygens Cable');
	} else {
	    $btnref->set_label('No Huygens Cable');
	}
	my $server_bandwidth=&get_value('status.server.settings.'.$profile.'.bandwidth');
	my $user_bandwidth=&get_value('status.client.settings.'.$profile.'.bandwidth');
	# we use the user bandwidth unless it hasn't been set
	my $bandwidth;
	if (!$user_bandwidth){
	    $bandwidth=$server_bandwidth;
	} else {
	    $bandwidth=$user_bandwidth;
	}
	# what selection have we got now?
	my $currselection=&get_value('status.client.settings.'.$profile.'.compressionMode');
	# remove all the existing entries from the drop box
	my $dropbox=&get_element_reference('status.client.settings.'.$profile.'.compressionMode');
	for (my $j=0;$j<${$status{'n_compression_options'}}[$i];$j++){
	    $dropbox->remove_text(0);
	}
	# start adding the new options
	${$status{'n_compression_options'}}[$i]=0;
	for (my $j=0;$j<=$#{$settings{'compression_modes'}};$j++){
	    if ((($huygens==${$settings{'compression_modes'}}[$j]->{'huygens'})||($huygens==TRUE))&&
		(($bandwidth==${$settings{'compression_modes'}}[$j]->{'bandwidth'})||
		 (($bandwidth<16)&&(${$settings{'compression_modes'}}[$j]->{'bandwidth'}==16)))){
		${$status{'n_compression_options'}}[$i]++;
		$dropbox->append_text(${$settings{'compression_modes'}}[$j]->{'mode'});
		if ($currselection){
		    if (${$settings{'compression_modes'}}[$j]->{'mode'} eq $currselection){
			$dropbox->set_active(${$status{'n_compression_options'}}[$i]-1);
		    }
		}
	    }
	}
    }
}

sub update_disk_options {
    for (my $i=0;$i<$status{'number_settings_windows'};$i++){
	my $profile=${$status{'settings_window_profileName'}}[$i];
	# what selection have we got now?
	my $currselection=&get_value('status.client.settings.'.$profile.'.selectedDisk');
	# remove all the existing entries from the drop box
	my $dropbox=&get_element_reference('status.client.settings.'.$profile.'.selectedDisk');
	for (my $j=0;$j<${$status{'n_disk_options'}}[$i];$j++){
	    $dropbox->remove_text(0);
	}
	# start adding the new options
	my $is_local=FALSE;
	my $is_remote=FALSE;
	for (my $j=0;$j<$status{'n_disks'};$j++){
	    if (${$status{'disks_recorders'}}[$j] eq 'local'){
		$is_local=TRUE;
	    } else {
		$is_remote=TRUE;
	    }
	}
	${$status{'n_disk_options'}}[$i]=0;
	my $diskdescription='any available disk';
	$dropbox->append_text($diskdescription);
	${$status{'n_disk_options'}}[$i]++;
	if ($currselection && ($diskdescription eq $currselection)){
	    $dropbox->set_active(${$status{'n_disk_options'}}[$i]-1);
	}
	# add the local disks
	if ($is_local==TRUE){
	    $diskdescription='any local disk';
	    $dropbox->append_text($diskdescription);
	    ${$status{'n_disk_options'}}[$i]++;
	    if ($currselection && ($diskdescription eq $currselection)){
		$dropbox->set_active(${$status{'n_disk_options'}}[$i]-1);
	    }
	    for (my $j=0;$j<$status{'n_disks'};$j++){
		if (${$status{'disks_recorders'}}[$j] eq 'local'){
		    $diskdescription=${$status{'disks_recorders'}}[$j].':'.${$status{'disks_disks'}}[$j];
		    $dropbox->append_text($diskdescription);
		    ${$status{'n_disk_options'}}[$i]++;
		    if ($currselection && ($diskdescription eq $currselection)){
			$dropbox->set_active(${$status{'n_disk_options'}}[$i]-1);
		    }
		}
	    }
	}
	# add the remote disks
	if ($is_remote==TRUE){
	    $diskdescription='any remote disk';
	    $dropbox->append_text($diskdescription);
	    ${$status{'n_disk_options'}}[$i]++;
	    if ($currselection && ($diskdescription eq $currselection)){
		$dropbox->set_active(${$status{'n_disk_options'}}[$i]-1);
	    }
	    for (my $j=0;$j<$status{'n_disks'};$j++){
		if (${$status{'disks_recorders'}}[$j] ne 'local'){
		    $diskdescription=${$status{'disks_recorders'}}[$j].':'.${$status{'disks_disks'}}[$j];
		    $dropbox->append_text($diskdescription);
		    ${$status{'n_disk_options'}}[$i]++;
		    if ($currselection && ($diskdescription eq $currselection)){
			$dropbox->set_active(${$status{'n_disk_options'}}[$i]-1);
		    }
		}
	    }
	}
    }
}

sub update_gui {
 
    # update our labels
    foreach my $key ( keys %gui_connections ) {
	if (ref($gui_connections{$key}) eq 'HASH'){
	    my %connection_hash=%{$gui_connections{$key}};
	    $connection_hash{'data'}=~/^(.*?)\.(.*)$/;
	    my $connector=$1;
	    my $connection=$2;
	    my $value;
	    if ($connector eq 'status'){
		$value=$status{$connection};
	    }
	    if ($key=~/Label$/){
		# it's a label we want to auto-update
		if ($gui_markup{$connection}){
		    $value="<span ".$gui_markup{$connection}.">".$value."</span>";
		}
		&set_value($connection_hash{'data'},$value);
	    }
	} elsif (ref($gui_connections{$key}) eq 'ARRAY'){
	    my @connection_array=@{$gui_connections{$key}};
	    for (my $i=0;$i<=$#connection_array;$i++){
		if (!$connection_array[$i]){
		    next;
		}
		my %connection_hash=%{$connection_array[$i]};
		$connection_hash{'data'}=~/^(.*?)\.(.*)$/;
		my $connector=$1;
		my $connection=$2;
		my $value;
		if ($connector eq 'status'){
		    $value=$status{$connection};
		}
		if ($key=~/Label$/){
		    # it's a label
		    if ($gui_markup{$connection}){
			$value="<span ".$gui_markup{$connection}.">".$value."</span>";
		    }
		    if (${$connection_hash{'element'}} && ${$connection_hash{'element'}} ne ""){
			&set_value($connection_hash{'data'},$value);
		    }
		}
	    }
	}
    }
    # update the compression drop boxes
    &update_compression_options();
    # update the disks
    # resize the table
    $gui_elements{'cMW_dF_tB_diskTable'}->resize($status{'n_disks'}+1,7);
    my @disktable_elements=('recorder','disk','label','size','free','percent','time');
    for (my $i=0;$i<$status{'n_disks'};$i++){
	for (my $j=0;$j<=$#disktable_elements;$j++){
	    if (${$status{'disk_table_labels'}}[$i][$j]){
		${$status{'disk_table_labels'}}[$i][$j]->set_markup(${$status{'disks_'.$disktable_elements[$j].'s'}}[$i]);
		${$status{'disk_table_labels'}}[$i][$j]->show;
	    } else {
		${$status{'disk_table_labels'}}[$i][$j]=Gtk2::Label->new(${$status{'disks_'.$disktable_elements[$j].'s'}}[$i]);
		$gui_elements{'cMW_dF_tB_diskTable'}->attach_defaults(${$status{'disk_table_labels'}}[$i][$j],
									      $j,$j+1,$i+1,$i+2);
		${$status{'disk_table_labels'}}[$i][$j]->show;
	    }
	}
    }
    # hide any disks above this
    for (my $i=$status{'n_disks'};$i<=$#{${status{'disk_table_labels'}}};$i++){
	for (my $j=0;$j<=$#disktable_elements;$j++){
	    ${$status{'disk_table_labels'}}[$i][$j]->hide;
	}
    }
    # update the disk drop boxes
    &update_disk_options();
    # update the remote host window
    &update_remote_hosts();
    # update our buttons
    # the settings profile buttons
    for (my $i=1;$i<$status{'number_settings_buttons'};$i++){
	# hide this button for now
	${$status{'settings_window_buttons'}}[$i]->hide;
	# disconnect the event
	${$status{'settings_window_buttons'}}[$i]->
	    signal_handler_disconnect(${$status{'settings_window_buttons_handles'}}[$i]);
    }
    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
	if (${$status{'settings_window_buttons'}}[$i]){
	    my $newlabel=${$status{'settings_window_profileName'}}[$i];
	    $newlabel=~s/_/__/g;
	    ${$status{'settings_window_buttons'}}[$i]->
		set_label($newlabel);
	    ${$status{'settings_window_buttons'}}[$i]->show;
	    # connect the right event
	    ${$status{'settings_window_buttons_handles'}}[$i]=
		${$status{'settings_window_buttons'}}[$i]->signal_connect('clicked',\&show_settings_window,$i);
	} else {
	    my $newlabel=${$status{'settings_window_profileName'}}[$i];
	    $newlabel=~s/_/__/g;
	    ${$status{'settings_window_buttons'}}[$i]=Gtk2::Button->new($newlabel);
	    # work out where to put this button in the table
	    my ($txloc,$tyloc)=($i-1,1);
	    while($txloc>$settings{'n_profile_columns'}-2){
		$txloc-=$settings{'n_profile_columns'}-1;
		$tyloc++;
	    }
	    $gui_elements{'cMW_sF_sBTB_settingsButtonsTable'}->
		attach_defaults(${$status{'settings_window_buttons'}}[$i],$txloc,$txloc+1,$tyloc,$tyloc+1);
	    ${$status{'settings_window_buttons'}}[$i]->show;
	    # connect the right event
	    ${$status{'settings_window_buttons_handles'}}[$i]=
		${$status{'settings_window_buttons'}}[$i]->signal_connect('clicked',\&show_settings_window,$i);
	}
    }
    $status{'number_settings_buttons'}=$status{'number_settings_windows'};
    # update the experiment buttons and queue window
    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
	${$gui_elements{'cSW_experimentProfileButton'}}[$i]->set_label('Add to Experiment Queue');
	my $is_experiment=FALSE;
	for (my $j=0;$j<=$#{$status{'queued_experiments'}};$j++){
	    if (${$status{'settings_window_profileName'}}[$i] eq
		${$status{'queued_experiments'}}[$j]->{'experiment'}){
		${$gui_elements{'cSW_experimentProfileButton'}}[$i]->set_label('Remove from Experiment Queue');
		&button_background_colour(\${$status{'settings_window_buttons'}}[$i],'white');
	    }
	}
	if ($is_experiment==FALSE){
	    &button_background_colour(\${$status{'settings_window_buttons'}}[$i],undef);
	}
    }
    my @queuetable_elements=('experiment','starttime','endtime');
    for (my $i=0;$i<=$#{$status{'queued_experiments'}};$i++){
	for (my $j=0;$j<=$#queuetable_elements;$j++){
	    if (${$status{'queue_table_labels'}}[$i][$j]){
		${$status{'queue_table_labels'}}[$i][$j]->
		    set_markup(${$status{'queued_experiments'}}[$i]->{$queuetable_elements[$j]});
		${$status{'queue_table_labels'}}[$i][$j]->show;
	    } else {
		${$status{'queue_table_labels'}}[$i][$j]=Gtk2::Label->
		    new(${$status{'queued_experiments'}}[$i]->{$queuetable_elements[$j]});
		$gui_elements{'cEQW_eQF_tB_queueTable'}->
		    attach_defaults(${$status{'queue_table_labels'}}[$i][$j],$j,$j+1,$i+1,$i+2);
		${$status{'queue_table_labels'}}[$i][$j]->show;
	    }
	}
    }
    # hide any experiments above this
    for (my $i=$#{$status{'queued_experiments'}}+1;$i<=$#{$status{'queue_table_labels'}};$i++){
	for (my $j=0;$j<=$#queuetable_elements;$j++){
	    ${$status{'queue_table_labels'}}[$i][$j]->hide;
	}
    }
    # the recorder control button
    &recording_button_state();
}

sub recorder_action {
    my $current_reclabel=&get_value('settings.recorderControl');

    &deregister_listener();
    
    if ($current_reclabel=~/^Start/){
	# start a recording
	if ($current_reclabel!~/Threaded/){
	    # we start a normal recording
	    my $comm_result=&server_comms('cmnd','record-start');
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to start recorder:\n".
				     $status{'communication_error'},'error');
	    } else {
		&print2messageBuffer("Recorder started.",'success');
		# show the recorder status window
		$gui_elements{'cdiskoRecordingWindow'}->show_all;
	    }
	} else {
	    # we start a threaded recording
	    my $thread_start_command='threads-start:';
	    my @threads_selected=&selected_threads();
	    for (my $i=0;$i<=$#threads_selected;$i++){
		if ($i>0){
		    $thread_start_command.=',';
		}
		$thread_start_command.=$threads_selected[$i]->{'name'};
	    }
	    my $comm_result=&server_comms('cmnd',$thread_start_command);
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to start thread recorder:\n",
				     $status{'communication_error'},'error');
	    } else {
		&print2messageBuffer("Thread recorder started.",'success');
		# show the recorder status window
		$gui_elements{'cdiskoRecordingWindow'}->show_all;
	    }
	}
    } else {
	# stop a recording
	if ($current_reclabel!~/Threaded/){
	    # we stop a normal recording
	    my $comm_result=&server_comms('cmnd','record-stop');
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to stop recorder:\n".
				     $status{'communication_error'},'error');
	    } else {
		&print2messageBuffer("Recorder stopped.",'success');
	    }
	} else {
	    # we stop a threaded recording
	    my $comm_result=&server_comms('cmnd','threads-stop');
	    if (!&success($comm_result)){
		&print2messageBuffer("Unable to stop thread recorder:\n",
				     $status{'communication_error'},'error');
	    } else {
		&print2messageBuffer("Thread recorder stopped.",'success');
	    }
	}
    }

    &register_listener();
}

sub recording_button_state {
    my $button_label;
    my $button_colour;
    if ($status{'server.recordingState'}=~/Not recording/){
	# change the colour of the recording status button
	my $btnref=&get_element_reference('status.server.recordingState');
	&button_background_colour(\$btnref,'bone');
	# what type of recording would we start? check for threaded recording selections
	my @threads_selected=&selected_threads();
	if ($#threads_selected>-1){
	    # make the button start a threaded recording
	    $button_label='Start Threaded Recording';
	    $button_colour='green';
	    # dehighlight the default button
	    &button_background_colour(\$gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'},undef);
	    # highlight the appropriate buttons
	    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
		&button_background_colour(\${$status{'settings_window_buttons'}}[$i],undef);
		for (my $j=0;$j<=$#threads_selected;$j++){
		    my $number=$threads_selected[$j]->{'number'};
		    if ($number==$i){
			&button_background_colour(\${$status{'settings_window_buttons'}}[$number],'green');
			last;
		    }
		}
	    }
	} else {
	    # make the button start a normal recording
	    # has the default profile got a delayed start time?
	    my $recstarttime=&get_value('status.server.settings.Default.recordStartTime');
	    if ($recstarttime eq 'not set'){
		$button_label='Start Immediate Recording';
		$button_colour='green';
	    } else {
		$button_label='Start Delayed Recording';
		$button_colour='green';
	    }
	    # dehighlight all the profile buttons
	    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
		&button_background_colour(\${$status{'settings_window_buttons'}}[$i],undef);
	    }
	    # highlight the default settings button
	    &button_background_colour(\$gui_elements{'cMW_sF_sBTB_sBT_defaultSettingsButton'},'green');
	}
    } else {
	# change the colour of the recording status button
	my $btnref=&get_element_reference('status.server.recordingState');
	&button_background_colour(\$btnref,'red');
	# make the button stop the recording
	$button_colour='red';
	if ($status{'thread_recording'}==FALSE){
	    $button_label='Stop Recording';
	} else {
	    $button_label='Stop Threaded Recording';
	}
    }
    $gui_elements{'cMW_sB_recorderControlButton'}->set_label($button_label);
    &button_background_colour(\$gui_elements{'cMW_sB_recorderControlButton'},$button_colour);
    
}

sub selected_threads {
    # find all the selected thread profiles
    my @threads_selected=();

    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
	my $is_selected=&get_value('status.client.settings.'.${$status{'settings_window_profileName'}}[$i].
				   '.includeThreaded');
	my $btnref=&get_element_reference('status.client.settings.'.${$status{'settings_window_profileName'}}[$i].
					  '.includeThreaded');
	if ($is_selected==TRUE){
	    my $selected_hash={ name => ${$status{'settings_window_profileName'}}[$i],
				number => $i };
	    push @threads_selected,$selected_hash;
	    $btnref->set_label('Included in threaded recording');
	} else {
	    $btnref->set_label('Not included in threaded recording');
	}	    
    }

    return @threads_selected;
}

sub show_settings_window {
    my ($buttonref,$number)=@_;

    ${$gui_elements{'cdiskoSettingsWindow'}}[$number]->show_all;
}

sub update_remote_hosts {
    # update the remote recorders
    my $ntotal_remote_enabled=0;
    my $ntotal_remote_available=0;
    my @remotetable_elements=('commonname','hostname','datacommunicationport','tcpwindowsize',
			      'udpenabled','evlbimode');
    # hide all elements of both tables now
    my @possible_tables=('cRHW_aF_tB_availableTable','cRHW_eF_tB_enabledTable');
    for (my $i=0;$i<=$#possible_tables;$i++){
	for (my $j=1;$j<=$#{$status{$possible_tables[$i].'_labels'}};$j++){
	    for (my $k=0;$k<=$#remotetable_elements;$k++){
		${$status{$possible_tables[$i].'_labels'}}[$j][$k]->hide;
	    }
	    # hide the buttons too
	    ${$status{$possible_tables[$i].'_buttons'}}[$j]->hide;
	}
    }
    for (my $i=1;$i<=$#{$settings{'remote_commonname'}};$i++){
	if (${$settings{'remote_commonname'}}[$i] ne ""){
	    my $intable='';
	    my $ntable;
	    my $tableaction;
	    if (${$settings{'remote_registered'}}[$i]==0){
		# not registered, we put it in the available frame
		$intable='cRHW_aF_tB_availableTable';
		$ntable=++$ntotal_remote_available;
		$tableaction='enable,'.$i;
	    } else {
		# it is registered, we put it in the enabled frame
		$intable='cRHW_eF_tB_enabledTable';
		$ntable=++$ntotal_remote_enabled;
		$tableaction='disable,'.$ntable;
	    }
	    # resize the appropriate table
	    $gui_elements{$intable}->resize($ntable+1,7);
	    # add the row
	    for (my $j=0;$j<=$#remotetable_elements;$j++){
		if (${$status{$intable.'_labels'}}[$ntable][$j]){
		    ${$status{$intable.'_labels'}}[$ntable][$j]->
			set_markup(${$settings{'remote_'.$remotetable_elements[$j]}}[$i]);
		    ${$status{$intable.'_labels'}}[$ntable][$j]->show;
		} else {
		    ${$status{$intable.'_labels'}}[$ntable][$j]=Gtk2::Label->new
			(${$settings{'remote_'.$remotetable_elements[$j]}}[$i]);
		    $gui_elements{$intable}->attach_defaults(${$status{$intable.'_labels'}}[$ntable][$j],$j,$j+1,
							     $ntable+1,$ntable+2);
		    ${$status{$intable.'_labels'}}[$ntable][$j]->show;
		}
	    }
	    # add a button
	    if (!${$status{$intable.'_buttons'}}[$ntable]){
		my $buttontext;
		my $buttoncolour;
		if ($intable eq 'cRHW_aF_tB_availableTable'){
		    $buttontext='Enable';
		    $buttoncolour='green';
		} elsif ($intable eq 'cRHW_eF_tB_enabledTable'){
		    $buttontext='Disable';
		    $buttoncolour='red';
		}
		${$status{$intable.'_buttons'}}[$ntable]=Gtk2::Button->new($buttontext);
		&button_background_colour(\${$status{$intable.'_buttons'}}[$ntable],$buttoncolour);
		$gui_elements{$intable}->attach_defaults(${$status{$intable.'_buttons'}}[$ntable],$#remotetable_elements+1,
							 $#remotetable_elements+2,$ntable+1,$ntable+2);
		${$status{$intable.'_buttons'}}[$ntable]->show;
	    } else {
		${$status{$intable.'_buttons'}}[$ntable]->show;
	    }
	    # set the action for the button
	    if (${$status{$intable.'_buttons_handles'}}[$ntable]){
		${$status{$intable.'_buttons'}}[$ntable]->
		    signal_handler_disconnect(${$status{$intable.'_buttons_handles'}}[$ntable]);
	    }		    
	    ${$status{$intable.'_buttons_handles'}}[$ntable]=
		${$status{$intable.'_buttons'}}[$ntable]->signal_connect('clicked',\&remotehost_actions,$tableaction);
	}
    }

}

sub remotehost_actions {
    my ($buttonref,$actionstring)=@_;

    $actionstring=~/(.*)\,(.*)/;
    my $action=$1;
    my $number=$2;
    if ($action eq "enable"){
	# enable a host, but which one?
	my $enable_commonname=${$settings{'remote_commonname'}}[$number];
	my $enable_hostname=${$settings{'remote_hostname'}}[$number];
	my $enable_datacommunicationport=${$settings{'remote_datacommunicationport'}}[$number];
	my $enable_tcpwindowsize=${$settings{'remote_tcpwindowsize'}}[$number];
	my $enable_evlbimode=${$settings{'remote_evlbimode'}}[$number];
	my $enable_recorderserverport=${$settings{'remote_recorderserverport'}}[$number];
	my $enable_udpenabled=${$settings{'remote_udpenabled'}}[$number];
	my $enable_ipd=${$settings{'remote_ipd'}}[$number];
	# do it
	my $comm_result=
	    &server_comms("data","add_host=".$enable_commonname.",".$enable_hostname.",".$enable_datacommunicationport.",".
			  $enable_tcpwindowsize.",".$enable_evlbimode.",".$enable_recorderserverport);
	if (&success($comm_result)){
	    if ($enable_udpenabled!=0){
		$comm_result=
		    &server_result("data","modify_host=".$enable_commonname.",".$enable_udpenabled.",".$enable_ipd);
		if (!&success($comm_result)){
		   &print2messageBuffer("Unable to enable ".$enable_commonname.":\n".
					$status{'communication_error'},'error');
	       }
	    }
	} else {
	    &print2messageBuffer("Unable to enable ".$enable_commonname.":\n".
				 $status{'communication_error'},'error');
	}
    } elsif ($action eq "disable"){
	# remove a host, but we have to get its name
	my $disable_commonname=${$status{'cRHW_eF_tB_enabledTable_labels'}}[$number][0]->get_text;
	# do it
	my $comm_result=&server_comms("data","rem_host=".$disable_commonname);
	if (!&success($comm_result)){
	    &print2messageBuffer("Unable to disable ".$disable_commonname.":\n".
				 $status{'communication_error'},'error');
	}
    }
}

sub button_background_colour {
    my ($buttonref, $colour)=@_;

    my $button=${$buttonref};

    my @elements=('normal','active','prelight');
    for (my $i=0;$i<=$#elements;$i++){
	if ($colour){
	    $button->modify_bg($elements[$i],$colours{$colour});
	} else {
	    $button->modify_bg($elements[$i],undef);
	}
    }
}

sub hide_settings_window {
    my ($eventref,$eventtype,$number)=@_;

    ${$gui_elements{'cdiskoSettingsWindow'}}[$number]->hide;
    return TRUE;
}

sub new_settings_window {
    my ($profilename)=@_;

    ${$status{'settings_window_profileName'}}[$status{'number_settings_windows'}]=$profilename;
    ${$gui_elements{'cdiskoSettingsWindow'}}[$status{'number_settings_windows'}]=Gtk2::Window->new;
    ${$gui_elements{'cdiskoSettingsWindow_closeHandle'}}[$status{'number_settings_windows'}]=
	${$gui_elements{'cdiskoSettingsWindow'}}[$status{'number_settings_windows'}]->
	signal_connect('delete_event',\&hide_settings_window,$status{'number_settings_windows'});
    ${$gui_elements{'cdiskoSettingsWindow'}}[$status{'number_settings_windows'}]->set_title($profilename.' Settings');
    &fill_settings_window(\${$gui_elements{'cdiskoSettingsWindow'}}[$status{'number_settings_windows'}],
			  $status{'number_settings_windows'});
    $status{'number_settings_windows'}++;
}

sub destroy_settings_window {
    my ($number)=@_;

    ${$gui_elements{'cdiskoSettingsWindow'}}[$number]->destroy;
    # go through all the settings windows above us and redo their close connection
    for (my $i=$number+1;$i<$status{'number_settings_windows'};$i++){
	${$gui_elements{'cdiskoSettingsWindow'}}[$i]->
	    signal_handler_disconnect(${$gui_elements{'cdiskoSettingsWindow_closeHandle'}}[$i]);
	${$gui_elements{'cdiskoSettingsWindow_closeHandle'}}[$i]=
	    ${$gui_elements{'cdiskoSettingsWindow'}}[$i]->
	    signal_connect('delete_event',\&hide_settings_window,$i-1);
    }
    $status{'number_settings_windows'}--;
}

sub interpret_status {
    
    # split up the response string
    my @response_split=split(/\n/,$status{'comm_result'});

    my $settingsname='';
    my $settingsthreadnumber=1;
    my @targetfound;
    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
	$targetfound[$i]=FALSE;
    }
    my $recordingdisknumber=0;
    $status{'server.recording.statistics'}='';
    $status{'thread_recording'}=FALSE;
    for (my $i=0;$i<=$#response_split;$i++){
#	print "! ".$response_split[$i]." !\n";
	if ($response_split[$i] eq ''){
	    next;
	}
	if ($response_split[$i]=~/^Server uptime\:\s(.*)/){
	    $status{'server.time.uptime'}=$1;
	    next;
	}
	if ($response_split[$i]=~/^Current Time\:\s(.*)/){
	    $status{'server.time.serverTime'}=$1;
	    next;
	}
	if ($response_split[$i]=~/^Recording Status\:\s(.*)/){
	    $status{'server.recordingState'}=$1;
	    # remove the silly looking full stop at the end
	    $status{'server.recordingState'}=~s/\.$//;
	    next;
	}
	if ($response_split[$i]=~/^Current Experiment\:/){
	    $status{'server.currentExperiment'}=$response_split[$i];
	    next;
	}
	if ($response_split[$i]=~/^Time until end\:/){
	    $status{'server.endTime'}=$response_split[$i];
	    next;
	}
	if ($response_split[$i]=~/^Disk Space\:/){
	    $status{'n_disks'}=0;
	    next;
	}
	if ($response_split[$i]=~/^\s\sdisk\s/){
	    my @els=split(/\s+/,$response_split[$i]);
	    my ($thisrecorder,$thisdisk,$thislabel,$thissize,$thisfree,$thispercent,$thistime);
	    if ($response_split[$i]=~/eVLBI recorder/){
		$els[2]=~s/[\[\]\:]//g;
		$thisrecorder=$els[2];
		$thisdisk=$els[3];
		$thislabel="";
		$thissize="";
		$thisfree="";
		$thispercent="";
		$thistime="";
	    } else {
		$els[3]=~s/[\[\]]//g;
		$els[3]=~s/\:$//g;
		if ($els[3]=~/(.*)\:(.*)/){
		    $thisrecorder=$1;
		    $thisdisk=$2;
		} else {
		    $thisdisk=$els[3];
		    $thisrecorder="local";
		}
		$response_split[$i]=~/.*\"(.*?)\".*TOTAL\: (.*) FREE\: (.*) \((.*)\) TIME\: (.*)$/;
		$thislabel=$1;
		$thissize=$2;
		$thisfree=$3;
		$thispercent=$4;
		$thistime=$5;
	    }
	    ${$status{'disks_recorders'}}[$status{'n_disks'}]=$thisrecorder;
	    ${$status{'disks_disks'}}[$status{'n_disks'}]=$thisdisk;
	    ${$status{'disks_labels'}}[$status{'n_disks'}]=$thislabel;
	    ${$status{'disks_sizes'}}[$status{'n_disks'}]=$thissize;
	    ${$status{'disks_frees'}}[$status{'n_disks'}]=$thisfree;
	    ${$status{'disks_percents'}}[$status{'n_disks'}]=$thispercent;
	    ${$status{'disks_times'}}[$status{'n_disks'}]=$thistime;
	    $status{'n_disks'}++;
	    next;
	}
	if ($response_split[$i]=~/^No remote recorders have been specified.*/){
	    # no remote host are known to the recorder, so we disable all the
	    # ones that we know are available
	    for (my $j=1;$j<=$#{$settings{'remote_commonname'}};$j++){
		if (${$settings{'remote_commonname'}}[$j] ne ""){
		    ${$settings{'remote_registered'}}[$j]=0;
		}
	    }
	    next;
	}
	if ($response_split[$i]=~/^Remote recorder.*/){
	    # a remote host is known
	    $response_split[$i]=~/.*?\"(.*)\"\:/;
	    my $foundhost=$1;
	    for (my $j=1;$j<=$#{$settings{'remote_commonname'}};$j++){
		if ($foundhost eq ${$settings{'remote_commonname'}}[$j]){
		    ${$settings{'remote_registered'}}[$j]=1;
		}
	    }
	    next;
	}
	if ($response_split[$i]=~/^Current Settings\:$/){
	    $settingsname='Default';
	    next;
	}
	if ($response_split[$i]=~/^Target \'(.*?)\'\:$/){
	    $settingsname=$1;
	    # check for this settings window
	    my $settingsfound=FALSE;
	    for (my $j=1;$j<$status{'number_settings_windows'};$j++){
		if ($settingsname eq ${$status{'settings_window_profileName'}}[$j]){
		    $settingsfound=TRUE;
		    $targetfound[$j]=TRUE;
		    last;
		}
	    }
	    if ($settingsfound==FALSE){
		# we need a new settings window
		&new_settings_window($settingsname);
		$targetfound[$status{'number_settings_windows'}-1]=TRUE;
	    }
	    next;
	}
	if ($response_split[$i]=~/^Recording Settings\:/){
	    $settingsname='recording';
	    next;
	}
	if ($response_split[$i]=~/^ Thread (\d+) settings\:/){
	    $status{'thread_recording'}=TRUE;
	    $settingsthreadnumber=$1;
	    next;
	}
	if ($response_split[$i]=~/ Record time\:\s+(\d+)(.*)$/){
	    # the recording time
	    if ($settingsname ne 'recording'){
		$status{'server.settings.'.$settingsname.'.recordTime'}=$1.' '.$2;
	    } else {
		$status{'server.recording.recordTime'}=$1.' '.$2;
	    }
	    next;
	}
	if ($response_split[$i]=~/ Output directory\:\s+(.*)$/) {
	    # the name of the experiment (maybe)
	    if ($settingsname ne 'recording'){
		$status{'server.settings.'.$settingsname.'.experimentName'}=$1;
	    } else {
		$status{'server.recording.experimentName'}=$1;
	    }
	    next;
	}
	if ($response_split[$i]=~/ Start date\:\s+(.*)$/){
	    # the start date of the experiment
	    if ($1 ne 'not set'){
		$status{'server.settings.'.$settingsname.'.recordStartTime'}=$1.' ';
	    } else {
		$status{'server.settings.'.$settingsname.'.recordStartTime'}='';
	    }
	    next;
	}
	if ($response_split[$i]=~/ Start time\:\s+(.*)$/){
	    # the start time of the experiment
	    $status{'server.settings.'.$settingsname.'.recordStartTime'}.=$1;
	    next;
	}
	if ($response_split[$i]=~/ Auto round start\:\s+(.*)$/){
	    # whether the start time of files are rounded to the nearest 10 second boundary
	    $status{'server.settings.'.$settingsname.'.autoRoundStart'}=$1;
	    next;
	}
	if ($response_split[$i]=~/ Mark5B recording\:\s+(.*)$/){
	    # whether we are recording to Mark 5B
	    $status{'server.settings.'.$settingsname.'.mark5B'}=$1;
	    next;
	}
	if ($response_split[$i]=~/ Target recorder\:\s+(.*)$/){
	    my $recmachine=$1;
	    if ($recmachine ne 'local'){
		$status{'server.settings.'.$settingsname.'.selectedDisk'}=$1.':';
	    } else {
		$status{'server.settings.'.$settingsname.'.selectedDisk'}='';
	    }
	    next;
	}
	if ($response_split[$i]=~/ Output disk\:\s+(.*)$/){
	    $status{'server.settings.'.$settingsname.'.selectedDisk'}.=$1.' ';
	    next;
	}
	if ($response_split[$i]=~/ Disk label\:\s+(.*)$/){
	    $status{'server.settings.'.$settingsname.'.selectedDisk'}.='('.$1.')';
	    next;
	}
	if ($response_split[$i]=~/ Auto disk select\:\s+(.*)$/){
	    my $diskselectmode=$1;
	    if ($diskselectmode eq 'any'){
		$status{'server.settings.'.$settingsname.'.selectedDisk'}='any available disk';
	    } elsif ($diskselectmode eq 'local'){
		$status{'server.settings.'.$settingsname.'.selectedDisk'}='any local disk';
	    } elsif ($diskselectmode eq 'remote'){
		$status{'server.settings.'.$settingsname.'.selectedDisk'}='any remote disk';
	    } elsif ($diskselectmode eq 'user-list'){
		$status{'server.settings.'.$settingsname.'.selectedDisk'}='any user-selected disk';
	    }
	    next;
	}
	if ($response_split[$i]=~/ Compression\:\s+(.*)$/){
	    if ($settingsname ne 'recording'){
		$status{'server.settings.'.$settingsname.'.compressionChannels'}=$1;
	    } else {
		$status{'server.recording.'.$settingsthreadnumber.'.compressionChannels'}=$1;
	    }
	    next;
	}
	if ($response_split[$i]=~/ VSIB Mode\:\s+(.*)$/){
	    if ($settingsname ne 'recording'){
		$status{'server.settings.'.$settingsname.'.vsibMode'}=$1;
	    } else {
		my $nbits;
		if ($1==3){
		    $nbits=8;
		} elsif ($1==2){
		    $nbits=16;
		}
		$status{'server.recording.nbits'}=$nbits;
	    }
	    next;
	}
	if ($response_split[$i]=~/ Bandwidth\:\s+(.*)$/){
	    if ($settingsname eq 'recording'){
		$status{'server.recording.bandwidth'}=$1;
	    } else {
		$status{'server.settings.'.$settingsname.'.bandwidth'}=$1;
		# we also have enough information now to determine the compression mode
		my $nbits=8;
		if ($status{'server.settings.'.$settingsname.'.vsibMode'}==2){
		    $nbits=16;
		}
		$status{'server.settings.'.$settingsname.'.compressionMode'}=''; # default in case nothing matches
		for (my $j=0;$j<=$#{$settings{'compression_modes'}};$j++){
		    if ((${$settings{'compression_modes'}}[$j]->{'nbits'}==$nbits)&&
			((${$settings{'compression_modes'}}[$j]->{'bandwidth'}==
			  $status{'server.settings.'.$settingsname.'.bandwidth'})||
			 (($status{'server.settings.'.$settingsname.'.bandwidth'}<16)&&
			  (${$settings{'compression_modes'}}[$j]->{'bandwidth'}==16)))&&
			(${$settings{'compression_modes'}}[$j]->{'compression'} eq
			 $status{'server.settings.'.$settingsname.'.compressionChannels'})&&
			((${$settings{'compression_modes'}}[$j]->{'huygens'}==FALSE)||
			 ((${$settings{'compression_modes'}}[$j]->{'huygens'}==TRUE)&&
			  (&get_value('status.client.settings.'.$settingsname.'.huygens')==TRUE)))){
			# this mode qualifies
			$status{'server.settings.'.$settingsname.'.compressionMode'}=
			    ${$settings{'compression_modes'}}[$j]->{'mode'};
			last;
		    }
		}
	    }
	    next;
	}
	if ($response_split[$i]=~/last file opened at day (\d+?)\, (.*?)\, block (\d+?) \((.*?)\)/){
	    $status{'server.recording.lastblock'}=$3;
	    $status{'server.recording.lastfile'}=$4;
	    next;
	}
	if ($response_split[$i]=~/recording to disk (.*?)\:(.*?) \((.*?)\)\, path (.*)/){
	    $status{'server.recording.recorder.target'.$recordingdisknumber}=$1;
	    $status{'server.recording.disk.target'.$recordingdisknumber}=$2;
	    $status{'server.recording.label.target'.$recordingdisknumber}=$3;
	    # find this disk for the other information
	    for (my $j=0;$j<$status{'n_disks'};$j++){
		if ((${$status{'disks_recorders'}}[$j] eq $1)&&
		    (${$status{'disks_disks'}}[$j] eq $2)){
		    $status{'server.recording.size.target'.$recordingdisknumber}=
			${$status{'disks_sizes'}}[$j];
		    $status{'server.recording.remaining.target'.$recordingdisknumber}=
			${$status{'disks_frees'}}[$j];
		    $status{'server.recording.rempercent.target'.$recordingdisknumber}=
			${$status{'disks_percents'}}[$j];
		    $status{'server.recording.remtime.target'.$recordingdisknumber}=
			${$status{'disks_times'}}[$j];
		    last;
		}
	    }
	    $recordingdisknumber++;
	    next;
	}
	if ($response_split[$i]=~/recording to eVLBI machine (.*?)\:/){
	    $status{'server.recording.recorder.target'.$recordingdisknumber}=$1;
	    $status{'server.recording.disk.target'.$recordingdisknumber}='eVLBI';
	    $status{'server.recording.label.target'.$recordingdisknumber}='';
	    $status{'server.recording.size.target'.$recordingdisknumber}='';
	    $status{'server.recording.remaining.target'.$recordingdisknumber}='';
	    $status{'server.recording.rempercent.target'.$recordingdisknumber}='';
	    $status{'server.recording.remtime.target'.$recordingdisknumber}='';
	    $recordingdisknumber++;
	    next;
	}
	if ($response_split[$i]=~/BIGBUF free memory \= (.*)/){
	    $status{'server.recording.lastbigbuf'}=$1;
	    if ($status{'server.recording.lastbigbuf'}=~/(.*?)\((.*?)\%\)/){
		my $pctbuf=$2;
		if ($pctbuf<50){
		    &print2messageBuffer("BIGBUF level down to ".$pctbuf."%!",'error');
		}
	    }
	    next;
	}
	if ($response_split[$i]=~/PPS missed (.*?) files/){
	    $status{'server.recording.missedpps'}=$1;
	    next;
	}
	if ($response_split[$i]=~/PPS signal OK/){
	    $status{'server.recording.lastpps'}='OK';
	    next;
	}
	if ($response_split[$i]=~/1PPS/){
	    $status{'server.recording.lastpps'}='Not OK';
	    &print2messageBuffer($response_split[$i],'error');
	    next;
	}
	if ($response_split[$i]=~/^Chan \d/){
	    # a line of the sampler statistics
	    if ($status{'server.recording.statistics'} eq ''){
		$status{'server.recording.statistics'}=$response_split[$i];
	    } else {
		$status{'server.recording.statistics'}.="\n".$response_split[$i];
	    }
	    next;
	}
	if ($response_split[$i]=~/^No experiments in queue/){
	    @{$status{'queued_experiments'}}=();
	    next;
	}
	if ($response_split[$i]=~/^Experiments in queue\:/){
	    @{$status{'queued_experiments'}}=();
	    next;
	}
	if ($response_split[$i]=~/^ Experiment \'(.*?)\'\: starts (.*?) ends (.*?)$/){
	    my $experimenthash={
		experiment => $1, starttime => $2, endtime => $3 };
	    push @{$status{'queued_experiments'}},$experimenthash;
	}
    }
    # check we've found each target we know about
    for (my $i=1;$i<$status{'number_settings_windows'};$i++){
	if ($targetfound[$i]==FALSE){
	    # don't know about this target anymore, so we destroy its window
	    &destroy_settings_window($i);
	    splice @{$gui_elements{'cdiskoSettingsWindow'}},$i,1;
	    splice @{$status{'settings_window_profileName'}},$i,1;
	}
    }
}

sub server_comms {
    my $type=shift;
    my $message=shift;
    my $flags=shift;

    # create the socket
    my $answer;
    my @machine = split(":",$localsettings->{'server'});
    my $socket = IO::Socket::INET->new(PeerAddr => $machine[0],
				       PeerPort => $machine[1]);

    if (!(defined($socket))){
	return("Can't connect to socket");
    }

    print $socket "<$type>$message</$type>";

    if (($flags)&&($flags==1)){
	# we may need to respond as a message client
	my $responded=FALSE;
	my $fh;
	my $temp;
	while ($responded==FALSE){
	    my @ready=$status{'selector'}->can_read();
	    if ($#ready<0){
		last;
	    }
	    foreach $fh (@ready) {
		if ($fh == $status{'listener'}){
		    my $ns=$fh->accept();
		    $status{'selector'}->add($ns);
		} else {
		    sysread $fh,$temp,1000;
		    if ($temp) {
			my $response="client acknowledged\0";
			syswrite $fh,$response,20;
			$responded=TRUE;
			$status{'selector'}->remove($fh);
			close $fh;
			last;
		    }
		}
	    }
	}
    }

    while(my $temp=<$socket>){
	if ($temp=~/\<fail\>/){
	    # do something with the error
	} elsif (($temp=~/\<status\>/)||($temp=~/\<\/status\>/)){
	    $temp=&strip_status($temp);
	}
	$answer.=$temp;
    }
    close($socket);

    if (!$answer){
	$answer='';
    }
    return $answer;
}

sub strip_status {
    my ($mesg) = @_;
    $mesg=~s/\<status\>//g;
    $mesg=~s/\<\/status\>//g;
    return $mesg;
}

sub strip_fail {
    my ($mesg) = @_;
    $mesg=~s/\<fail\>//;
    $mesg=~s/\<\/fail\>(.*)//;
    return ($mesg);
}

sub success {
    # check for the success flag from a communication with the
    # recorder server, and if return 1 if we find it.
    # otherwise, an error has occurred and we return 0 and set
    # the global variable $communication_error to the failure
    # message
    my $check_communication = $_[0];
    if (!$check_communication){
	return 0;
    }
    my $retval=1;
    if ($check_communication=~/\<succ\s\/\>/){
	# communication was successful
	$status{'communication_error'}="";
	$retval=1;
    } elsif ($check_communication=~/^\<fail\>/) {
	# there was a failure code
	$status{'communication_error'}=&strip_fail($check_communication);
	$retval=0;
    }
    return $retval;
}

sub configfile_read_remote_hosts {
    my ($localsettings)=@_;

    # we recognise a maximum of 20 remote recorders
    for (my $i=1;$i<=20;$i++){
	if ($localsettings->{'remote_host'.$i}){
	    ${$settings{'remote_hostname'}}[$i]=$localsettings->{'remote_host'.$i};
	    if ($localsettings->{'remote_common'.$i}){
		${$settings{'remote_commonname'}}[$i]=$localsettings->{'remote_common'.$i};
	    } else {
		$localsettings->{'remote_host'.$i}=~/^(.*?)\..*$/;
		${$settings{'remote_commonname'}}[$i]=$1;
	    }
	} else {
	    ${$settings{'remote_hostname'}}[$i]="";
	    ${$settings{'remote_hostname'}}[$i]="";
	}
	if ($localsettings->{'tcp_port'.$i}){
	    ${$settings{'remote_datacommunicationport'}}[$i]=$localsettings->{'tcp_port'.$i};
	} else {
	    ${$settings{'remote_datacommunicationport'}}[$i]=-1;
	}
	if ($localsettings->{'tcp_window_size'.$i}){
	    ${$settings{'remote_tcpwindowsize'}}[$i]=$localsettings->{'tcp_window_size'.$i};
	} else {
	    ${$settings{'remote_tcpwindowsize'}}[$i]=-1;
	}
	if ($localsettings->{'evlbi'.$i}){
	    ${$settings{'remote_evlbimode'}}[$i]=$localsettings->{'evlbi'.$i};
	} else {
	    ${$settings{'remote_evlbimode'}}[$i]=0;
	}
	if ($localsettings->{'recorder_server_port'.$i}){
	    ${$settings{'remote_recorderserverport'}}[$i]=$localsettings->{'recorder_server_port'.$i};
	} else {
	    ${$settings{'remote_recorderserverport'}}[$i]=50080;
	}
	if ($localsettings->{'udp'.$i}){
	    ${$settings{'remote_udpenabled'}}[$i]=$localsettings->{'udp'.$i};
	} else {
	    ${$settings{'remote_udpenabled'}}[$i]=0;
	}
	if ($localsettings->{'ipd'.$i}){
	    ${$settings{'remote_ipd'}}[$i]=$localsettings->{'ipd'.$i};
	} else {
	    ${$settings{'remote_ipd'}}[$i]=0;
	}
    }
}

sub assign_compression_modes {
    # assign all the possible compression modes

    # 1 DAS, no Huygens cable, bandwidth <= 16 MHz
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 1', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'ooox' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 2', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'ooxo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 3', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'oxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 4', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'xooo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,2', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'ooxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,3', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'oxox' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 3,4', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'xxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 2,4', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'xoxo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1 -> 4', nbits => 8, bandwidth => 16, huygens => FALSE, compression => 'xxxx' };
    # 2 DAS, Huygens cable, bandwidth <= 16 MHz
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,5', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'ooox' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 2,6', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'ooxo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 3,7', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'oxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 4,8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xooo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,2,5,6', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'ooxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,3,5,7', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'oxox' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 2,4,6,8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xoxo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 3,4,7,8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,2,7,8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xxooooxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 3,4,5,6', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'ooxxxxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1 -> 8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xxxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 5 -> 8', nbits => 16, bandwidth => 16, huygens => TRUE, compression => 'xo' };
    # 1 DAS, no Huygens cable, bandwidth = 32 MHz
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 1', nbits => 8, bandwidth => 32, huygens => FALSE, compression => 'ooxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 2', nbits => 8, bandwidth => 32, huygens => FALSE, compression => 'xxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,2', nbits => 8, bandwidth => 32, huygens => FALSE, compression => 'xxxx' };
    # 2 DAS, Huygens cable, bandwidth = 32 MHz
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,3', nbits => 16, bandwidth => 32, huygens => TRUE, compression => 'ooxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 2,4', nbits => 16, bandwidth => 32, huygens => TRUE, compression => 'xxoo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1 -> 4', nbits => 16, bandwidth => 32, huygens => TRUE, compression => 'xxxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 5 -> 8', nbits => 16, bandwidth => 32, huygens => TRUE, compression => 'xo' };
    # 1 DAS, no Huygens cable, bandwidth = 64 MHz
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 1', nbits => 8, bandwidth => 64, huygens => FALSE, compression => 'xxxx' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chan 2', nbits => 16, bandwidth => 64, huygens => FALSE, compression => 'xo' };
    push @{$settings{'compression_modes'}}, {
	mode => 'Chans 1,2', nbits => 16, bandwidth => 64, huygens => FALSE, compression => 'xxxx' };
    
}

sub make_listener {
    $status{'listener'}=new IO::Socket::INET(Listen => 1,
					     LocalPort => $settings{'listenport'},
					     ReuseAddr => 1,
					     Proto => 'tcp',
					     MultiHomed => 1);
    if (!$status{'listener'}){
	return;
    }
    $status{'selector'}=new IO::Select($status{'listener'});

    # use Gtk to handle the actions when the socket is written to
    $status{'helper'}=Gtk2::Helper->add_watch( fileno $status{'listener'}, 'in',\&respond_listener, $status{'listener'});
}

sub respond_listener {
    my ($fd,$condition,$fh)=@_;
    my $temp;
    my $ns=$fh->accept;
    sysread $ns,$temp,1000;
    if ($temp){
	&print2messageBuffer($temp,'serverMessage');
	my $response="client acknowledged\0";
	syswrite $ns,$response,20;
    }
    return TRUE;
}

sub register_listener {
    if (!$status{'listener'}){
	return;
    }
    my $comm_result=&server_comms('cmnd','client-register',1);
}

sub deregister_listener {
    if (!$status{'listener'}){
	return;
    }
    my $comm_result=&server_comms('cmnd','client-remove');
}
